From 92c12e99554ae13777edc8178e9a15052864de3e Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 9 Jan 2024 16:16:41 +0100 Subject: [PATCH 01/69] Remove FareComponent --- ...CombinedInterlinedLegsFareServiceTest.java | 8 +- .../fares/impl/DefaultFareServiceTest.java | 46 ++++++------ .../ext/fares/impl/FaresIntegrationTest.java | 5 +- .../ext/fares/impl/HSLFareServiceTest.java | 6 +- ...reInFreeTransferWindowFareServiceTest.java | 4 +- .../ext/fares/FaresToItineraryMapper.java | 1 - .../ext/fares/impl/DefaultFareService.java | 23 +++--- .../ext/restapi/mapping/FareMapper.java | 14 +--- .../apis/gtfs/GtfsGraphQLIndex.java | 2 - .../apis/gtfs/datafetchers/ItineraryImpl.java | 3 +- .../gtfs/datafetchers/fareComponentImpl.java | 48 ------------ .../apis/gtfs/datafetchers/fareImpl.java | 6 +- .../gtfs/generated/GraphQLDataFetchers.java | 3 +- .../apis/gtfs/generated/graphql-codegen.yml | 1 - .../model/fare/ItineraryFares.java | 75 ++----------------- .../routing/core/FareComponent.java | 21 ------ .../apis/gtfs/GraphQLIntegrationTest.java | 5 -- 17 files changed, 61 insertions(+), 210 deletions(-) delete mode 100644 src/main/java/org/opentripplanner/apis/gtfs/datafetchers/fareComponentImpl.java delete mode 100644 src/main/java/org/opentripplanner/routing/core/FareComponent.java diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedLegsFareServiceTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedLegsFareServiceTest.java index c5901a0269e..dde40e06cef 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedLegsFareServiceTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedLegsFareServiceTest.java @@ -69,11 +69,11 @@ void modes(CombinationMode mode, Itinerary itinerary, Money totalPrice, String h assertEquals(totalPrice, price); var firstLeg = itinerary.getTransitLeg(0); - var uses = fare.legProductsFromComponents().get(firstLeg); + var uses = fare.getLegProducts().get(firstLeg); assertEquals(1, uses.size()); var secondLeg = itinerary.getTransitLeg(1); - uses = fare.legProductsFromComponents().get(secondLeg); + uses = fare.getLegProducts().get(secondLeg); assertEquals(1, uses.size()); } @@ -89,14 +89,14 @@ void legFares() { var fare = service.calculateFares(itinerary); var firstLeg = itinerary.getTransitLeg(0); - var uses = List.copyOf(fare.legProductsFromComponents().get(firstLeg)); + var uses = List.copyOf(fare.getLegProducts().get(firstLeg)); assertEquals(1, uses.size()); var firstLegUse = uses.get(0); assertEquals(tenDollars, firstLegUse.product().price()); var secondLeg = itinerary.getTransitLeg(1); - uses = List.copyOf(fare.legProductsFromComponents().get(secondLeg)); + uses = List.copyOf(fare.getLegProducts().get(secondLeg)); assertEquals(1, uses.size()); var secondLegUse = uses.get(0); diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java index 768e586da31..c0daa7bd3c0 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java @@ -3,7 +3,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.opentripplanner.ext.fares.impl.FareModelForTest.AIRPORT_STOP; import static org.opentripplanner.ext.fares.impl.FareModelForTest.AIRPORT_TO_CITY_CENTER_SET; import static org.opentripplanner.ext.fares.impl.FareModelForTest.CITY_CENTER_A_STOP; @@ -56,13 +55,10 @@ void simpleZoneBasedFare() { assertEquals(TEN_DOLLARS, fp.price()); assertEquals("F:regular", fp.id().toString()); - var lp = fare.legProductsFromComponents(); + var lp = fare.getLegProducts(); assertEquals(1, lp.size()); var product = lp.values().iterator().next().product(); assertEquals(TEN_DOLLARS, product.price()); - - // the leg products from the components and the "true" leg products are different collections - assertTrue(fare.getLegProducts().isEmpty()); } @Test @@ -91,9 +87,7 @@ void shouldNotCombineInterlinedLegs() { assertEquals(TWENTY_DOLLARS, price); - assertTrue(fare.getLegProducts().isEmpty()); - - var legProductsFromComponents = fare.legProductsFromComponents(); + var legProductsFromComponents = fare.getLegProducts(); var firstLeg = itin.getLegs().get(0); var products = List.copyOf(legProductsFromComponents.get(firstLeg)); @@ -124,18 +118,18 @@ void unknownLeg() { var price = fare.getFare(FareType.regular); assertEquals(Money.usDollars(-0.01f), price); - var components = fare.getComponents(FareType.regular); - assertEquals(1, components.size()); + var fareProducts = List.copyOf(fare.getLegProducts().values()); + assertEquals(1, fareProducts.size()); - var component = components.get(0); - assertEquals(AIRPORT_TO_CITY_CENTER_SET.getFareAttribute().getId(), component.fareId()); - assertEquals(TEN_DOLLARS, component.price()); + var fp = fareProducts.get(0).product(); + assertEquals(AIRPORT_TO_CITY_CENTER_SET.getFareAttribute().getId(), fp.id()); + assertEquals(TEN_DOLLARS, fp.price()); var firstBusLeg = itin.firstTransitLeg().get(); - assertEquals(List.of(firstBusLeg), component.legs()); + //assertEquals(List.of(firstBusLeg), fp.legs()); - var legProductsFromComponent = fare.legProductsFromComponents(); - assertEquals(1, legProductsFromComponent.size()); + var legProducts = fare.getLegProducts(); + assertEquals(1, legProducts.size()); } @Test @@ -150,18 +144,18 @@ void multipleFeeds() { var result = service.calculateFares(itin); var resultComponents = result - .getComponents(FareType.regular) + .getLegProducts() + .values() .stream() - .map(r -> r.fareId()) + .map(r -> r.product().id()) .toList(); - var resultPrice = result.getFare(FareType.regular); - assertEquals( List.of(AIRPORT_TO_CITY_CENTER_SET.getFareAttribute().getId(), OTHER_FEED_ATTRIBUTE.getId()), resultComponents ); + var resultPrice = result.getFare(FareType.regular); assertEquals(TWENTY_DOLLARS, resultPrice); } @@ -179,17 +173,18 @@ void multipleFeedsWithTransfersWithinFeed() { var result = service.calculateFares(itin); var resultComponents = result - .getComponents(FareType.regular) + .getLegProducts() + .values() .stream() - .map(r -> r.fareId()) + .map(r -> r.product().id()) .toList(); - var resultPrice = result.getFare(FareType.regular); assertEquals( List.of(INSIDE_CITY_CENTER_SET.getFareAttribute().getId(), OTHER_FEED_ATTRIBUTE.getId()), resultComponents ); + var resultPrice = result.getFare(FareType.regular); assertEquals(TWENTY_DOLLARS, resultPrice); } @@ -204,9 +199,10 @@ void multipleFeedsWithUnknownFareLegs() { .build(); var result = service.calculateFares(itin); var resultComponents = result - .getComponents(FareType.regular) + .getLegProducts() + .values() .stream() - .map(r -> r.fareId()) + .map(r -> r.product().id()) .toList(); var resultPrice = result.getFare(FareType.regular); assertEquals(List.of(OTHER_FEED_ATTRIBUTE.getId()), resultComponents); diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/impl/FaresIntegrationTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/impl/FaresIntegrationTest.java index 939d05cb2c2..ecf06c6b7df 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/impl/FaresIntegrationTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/impl/FaresIntegrationTest.java @@ -24,7 +24,6 @@ import org.opentripplanner.standalone.api.OtpServerRequestContext; import org.opentripplanner.test.support.ResourceLoader; import org.opentripplanner.transit.model.basic.Money; -import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.service.TransitModel; public class FaresIntegrationTest { @@ -130,7 +129,7 @@ public void testFareComponent() { var to = GenericLocation.fromStopId("Destination", feedId, "B"); var fare = getFare(from, to, dateTime, serverContext); - + /* var fareComponents = fare.getComponents(FareType.regular); assertEquals(fareComponents.size(), 1); assertEquals(fareComponents.get(0).price(), tenUSD); @@ -220,6 +219,8 @@ public void testFareComponent() { assertEquals(fareComponents.get(1).fareId(), new FeedScopedId(feedId, "BD")); assertEquals(fareComponents.get(1).routes().get(0), new FeedScopedId(feedId, "2")); assertEquals(fareComponents.get(1).routes().get(1), new FeedScopedId(feedId, "3")); + + */ } private static ItineraryFares getFare( diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/impl/HSLFareServiceTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/impl/HSLFareServiceTest.java index 14fbe18f792..a094a01412b 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/impl/HSLFareServiceTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/impl/HSLFareServiceTest.java @@ -18,7 +18,6 @@ import org.opentripplanner.model.plan.Itinerary; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.PlanTestConstants; -import org.opentripplanner.routing.core.FareComponent; import org.opentripplanner.routing.core.FareType; import org.opentripplanner.routing.fares.FareService; import org.opentripplanner.transit.model._data.TransitModelForTest; @@ -43,9 +42,10 @@ public void canCalculateHSLFares( expectedFareIds.toArray(), fareService .calculateFares(i) - .getComponents(FareType.regular) + .getLegProducts() + .values() .stream() - .map(FareComponent::fareId) + .map(u -> u.product().id()) .toArray() ); } diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/impl/HighestFareInFreeTransferWindowFareServiceTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/impl/HighestFareInFreeTransferWindowFareServiceTest.java index 57621c9ab0f..48dd6b520c5 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/impl/HighestFareInFreeTransferWindowFareServiceTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/impl/HighestFareInFreeTransferWindowFareServiceTest.java @@ -1,7 +1,7 @@ package org.opentripplanner.ext.fares.impl; -import static graphql.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.opentripplanner.model.plan.TestItineraryBuilder.newItinerary; import static org.opentripplanner.transit.model._data.TransitModelForTest.FEED_ID; import static org.opentripplanner.transit.model._data.TransitModelForTest.id; @@ -46,7 +46,7 @@ public void canCalculateFare( assertEquals(expectedFare, fares.getFare(FareType.regular)); for (var type : fares.getFareTypes()) { - assertTrue(fares.getComponents(type).isEmpty()); + assertFalse(fares.getLegProducts().isEmpty()); var prices = fares .getItineraryProducts() diff --git a/src/ext/java/org/opentripplanner/ext/fares/FaresToItineraryMapper.java b/src/ext/java/org/opentripplanner/ext/fares/FaresToItineraryMapper.java index a2b0984e4a3..f4a871b3ceb 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/FaresToItineraryMapper.java +++ b/src/ext/java/org/opentripplanner/ext/fares/FaresToItineraryMapper.java @@ -1,6 +1,5 @@ package org.opentripplanner.ext.fares; -import com.google.common.collect.Multimap; import org.opentripplanner.framework.collection.ListUtils; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.fare.ItineraryFares; diff --git a/src/ext/java/org/opentripplanner/ext/fares/impl/DefaultFareService.java b/src/ext/java/org/opentripplanner/ext/fares/impl/DefaultFareService.java index 6b7081de5ec..a39ccebe0e7 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/impl/DefaultFareService.java +++ b/src/ext/java/org/opentripplanner/ext/fares/impl/DefaultFareService.java @@ -1,5 +1,7 @@ package org.opentripplanner.ext.fares.impl; +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Multimap; import java.time.Duration; import java.time.ZonedDateTime; import java.util.ArrayList; @@ -18,11 +20,11 @@ import org.opentripplanner.ext.fares.model.FareRuleSet; import org.opentripplanner.ext.flex.FlexibleTransitLeg; import org.opentripplanner.model.fare.FareProduct; +import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.fare.ItineraryFares; import org.opentripplanner.model.plan.Itinerary; import org.opentripplanner.model.plan.Leg; import org.opentripplanner.model.plan.ScheduledTransitLeg; -import org.opentripplanner.routing.core.FareComponent; import org.opentripplanner.routing.core.FareType; import org.opentripplanner.routing.fares.FareService; import org.opentripplanner.transit.model.basic.Money; @@ -119,7 +121,7 @@ public ItineraryFares calculateFares(Itinerary itinerary) { ItineraryFares fare = ItineraryFares.empty(); boolean hasFare = false; for (FareType fareType : fareRulesPerType.keySet()) { - List components = new ArrayList<>(); + final Multimap fareProducts = LinkedHashMultimap.create(); List fares = new ArrayList<>(); boolean legWithoutRulesFound = false; boolean legsWithoutMatchingRulesFound = false; @@ -143,7 +145,7 @@ public ItineraryFares calculateFares(Itinerary itinerary) { } hasFare = feedHasFare || hasFare; // Other feeds might still have fare for some legs - components.addAll(currentFare.getComponents(fareType)); + fareProducts.putAll(currentFare.getLegProducts()); fare.addFare(fareType, currentFare.getFare(fareType)); currentFare @@ -170,7 +172,7 @@ public ItineraryFares calculateFares(Itinerary itinerary) { } } - fare.addFareComponent(fareType, components); + fare.addFareProductUses(fareProducts); // No fares will be discovered after this point if (!hasFare) { @@ -244,7 +246,7 @@ protected boolean populateFare( ) { FareSearch r = performSearch(fareType, legs, fareRules); - List components = new ArrayList<>(); + Multimap legProducts = LinkedHashMultimap.create(); int count = 0; int start = 0; int end = legs.size() - 1; @@ -276,16 +278,19 @@ protected boolean populateFare( componentLegs.add(leg); } } - components.add( - new FareComponent(fareId, Money.ofFractionalAmount(currency, cost), componentLegs) - ); + + var product = FareProduct + .of(fareId, fareId.toString(), Money.ofFractionalAmount(currency, cost)) + .build(); + componentLegs.forEach(l -> legProducts.put(l, product)); + ++count; start = via + 1; } var amount = r.resultTable[0][legs.size() - 1]; fare.addFare(fareType, Money.ofFractionalAmount(currency, amount)); - fare.addFareComponent(fareType, components); + fare.addFareProducts(legProducts); return count > 0; } diff --git a/src/ext/java/org/opentripplanner/ext/restapi/mapping/FareMapper.java b/src/ext/java/org/opentripplanner/ext/restapi/mapping/FareMapper.java index a6020c6bf37..7eb0d26339e 100644 --- a/src/ext/java/org/opentripplanner/ext/restapi/mapping/FareMapper.java +++ b/src/ext/java/org/opentripplanner/ext/restapi/mapping/FareMapper.java @@ -24,7 +24,6 @@ import org.opentripplanner.model.fare.RiderCategory; import org.opentripplanner.model.plan.Itinerary; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.routing.core.FareComponent; import org.opentripplanner.transit.model.basic.Money; public class FareMapper { @@ -106,14 +105,7 @@ private List toApiFareProducts(Collection product) } private Map> toApiFareComponents(ItineraryFares fare) { - return fare - .getFareTypes() - .stream() - .map(key -> { - var money = fare.getComponents(key).stream().map(this::toApiFareComponent).toList(); - return new SimpleEntry<>(key, money); - }) - .collect(Collectors.toMap(e -> e.getKey().name(), Entry::getValue)); + return Map.of(); } private Map toApiMoneys(ItineraryFares fare) { @@ -139,8 +131,4 @@ private ApiMoney toApiMoney(Money m) { ) ); } - - private ApiFareComponent toApiFareComponent(FareComponent m) { - return new ApiFareComponent(m.fareId(), null, toApiMoney(m.price()), m.routes()); - } } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java index b50bbaa9b9e..7101d132834 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java @@ -77,7 +77,6 @@ import org.opentripplanner.apis.gtfs.datafetchers.VehicleRentalStationImpl; import org.opentripplanner.apis.gtfs.datafetchers.debugOutputImpl; import org.opentripplanner.apis.gtfs.datafetchers.elevationProfileComponentImpl; -import org.opentripplanner.apis.gtfs.datafetchers.fareComponentImpl; import org.opentripplanner.apis.gtfs.datafetchers.fareImpl; import org.opentripplanner.apis.gtfs.datafetchers.placeAtDistanceImpl; import org.opentripplanner.apis.gtfs.datafetchers.serviceTimeRangeImpl; @@ -129,7 +128,6 @@ protected static GraphQLSchema buildSchema() { .type(typeWiring.build(debugOutputImpl.class)) .type(typeWiring.build(DepartureRowImpl.class)) .type(typeWiring.build(elevationProfileComponentImpl.class)) - .type(typeWiring.build(fareComponentImpl.class)) .type(typeWiring.build(fareImpl.class)) .type(typeWiring.build(FeedImpl.class)) .type(typeWiring.build(FeedImpl.class)) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ItineraryImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ItineraryImpl.java index 5e0ee6285a8..5399783bee0 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ItineraryImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ItineraryImpl.java @@ -3,6 +3,7 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; @@ -54,7 +55,7 @@ public DataFetcher>> fares() { Map result = new HashMap<>(); result.put("name", fareKey); result.put("fare", fare.getFare(fareKey)); - result.put("details", fare.getComponents(fareKey)); + result.put("details", List.of()); return result; }) .collect(Collectors.toList()); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/fareComponentImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/fareComponentImpl.java deleted file mode 100644 index a8c1b4d38f5..00000000000 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/fareComponentImpl.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.opentripplanner.apis.gtfs.datafetchers; - -import graphql.schema.DataFetcher; -import graphql.schema.DataFetchingEnvironment; -import java.util.stream.Collectors; -import org.opentripplanner.apis.gtfs.GraphQLRequestContext; -import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; -import org.opentripplanner.routing.core.FareComponent; -import org.opentripplanner.transit.model.network.Route; -import org.opentripplanner.transit.service.TransitService; - -public class fareComponentImpl implements GraphQLDataFetchers.GraphQLFareComponent { - - @Override - public DataFetcher cents() { - return environment -> getSource(environment).price().minorUnitAmount(); - } - - @Override - public DataFetcher currency() { - return environment -> getSource(environment).price().currency().getCurrencyCode(); - } - - @Override - public DataFetcher fareId() { - return environment -> getSource(environment).fareId().toString(); - } - - @Override - public DataFetcher> routes() { - return environment -> { - TransitService transitService = getTransitService(environment); - return getSource(environment) - .routes() - .stream() - .map(transitService::getRouteForId) - .collect(Collectors.toList()); - }; - } - - private TransitService getTransitService(DataFetchingEnvironment environment) { - return environment.getContext().transitService(); - } - - private FareComponent getSource(DataFetchingEnvironment environment) { - return environment.getSource(); - } -} diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/fareImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/fareImpl.java index e1986d215be..fb2c6ee184c 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/fareImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/fareImpl.java @@ -2,9 +2,9 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; +import java.util.List; import java.util.Map; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; -import org.opentripplanner.routing.core.FareComponent; import org.opentripplanner.transit.model.basic.Money; public class fareImpl implements GraphQLDataFetchers.GraphQLFare { @@ -15,8 +15,8 @@ public DataFetcher cents() { } @Override - public DataFetcher> components() { - return environment -> (Iterable) getSource(environment).get("details"); + public DataFetcher> components() { + return environment -> List.of(); } @Override diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index d89453be056..cd002ec187b 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -40,7 +40,6 @@ import org.opentripplanner.model.plan.WalkStep; import org.opentripplanner.routing.alertpatch.TransitAlert; import org.opentripplanner.routing.api.response.RoutingError; -import org.opentripplanner.routing.core.FareComponent; import org.opentripplanner.routing.graphfinder.NearbyStop; import org.opentripplanner.routing.graphfinder.PatternAtStop; import org.opentripplanner.routing.graphfinder.PlaceAtDistance; @@ -1239,7 +1238,7 @@ public interface GraphQLElevationProfileComponent { public interface GraphQLFare { public DataFetcher cents(); - public DataFetcher> components(); + public DataFetcher> components(); public DataFetcher currency(); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index 68901bdccef..c720fc5a119 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -55,7 +55,6 @@ config: elevationProfileComponent: org.opentripplanner.model.plan.ElevationProfile.Step Emissions: org.opentripplanner.model.plan.Emissions#Emissions fare: java.util.Map#Map - fareComponent: org.opentripplanner.routing.core.FareComponent#FareComponent Feed: String Geometry: org.locationtech.jts.geom.Geometry#Geometry InputField: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLInputField#GraphQLInputField diff --git a/src/main/java/org/opentripplanner/model/fare/ItineraryFares.java b/src/main/java/org/opentripplanner/model/fare/ItineraryFares.java index 0f9f815efe6..3443c01a062 100644 --- a/src/main/java/org/opentripplanner/model/fare/ItineraryFares.java +++ b/src/main/java/org/opentripplanner/model/fare/ItineraryFares.java @@ -1,6 +1,5 @@ package org.opentripplanner.model.fare; -import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Multimap; @@ -11,12 +10,10 @@ import java.util.Map; import java.util.Objects; import java.util.Set; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.opentripplanner.framework.lang.Sandbox; import org.opentripplanner.framework.tostring.ToStringBuilder; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.routing.core.FareComponent; import org.opentripplanner.routing.core.FareType; import org.opentripplanner.transit.model.basic.Money; @@ -41,19 +38,6 @@ public class ItineraryFares { */ private final Multimap legProducts = LinkedHashMultimap.create(); - /** - * The fares V1 fare "components" that apply to individual legs (not the entire price of the - * itinerary). - *

- * This is an ill-thought-out concept that was bolted onto the existing implementation in 2016 and - * is going to be removed once HSL has migrated off it. - *

- * Note: LinkedHashMultimap keeps the insertion order - * @deprecated Exists only for backwards compatibility and will be removed in the future. - */ - @Deprecated - private final Multimap components = LinkedHashMultimap.create(); - /** * Holds the "fares" for the entire itinerary. The definition of a fare is not clear so * this is deprecated. @@ -93,19 +77,6 @@ public void addFare(FareType fareType, Money money) { fares.put(fareType, money); } - /** - * Add a collection of "fare components" for a type. These concepts are ill-defined and will be - * removed in the future. - *

- * @deprecated Only exitst for backwards compatibility. - * Use @{link {@link ItineraryFares#addItineraryProducts(Collection)}}, - * {@link ItineraryFares#addFareProduct(Leg, FareProduct)} or - */ - @Deprecated - public void addFareComponent(FareType fareType, List components) { - this.components.replaceValues(fareType, components); - } - /** * Add fare products that cover the entire itinerary, i.e. are valid for all legs. */ @@ -127,17 +98,6 @@ public Money getFare(FareType type) { return fares.get(type); } - /** - * Get the "components" of a fare for a specific type. - *

- * Use {@link ItineraryFares#getItineraryProducts()} or {@link ItineraryFares#getLegProducts()} - * instead. - */ - @Deprecated - public List getComponents(FareType type) { - return List.copyOf(components.get(type)); - } - /** * Return the set of {@link FareType}s that are contained in this instance. */ @@ -148,7 +108,7 @@ public Set getFareTypes() { @Override public int hashCode() { - return Objects.hash(itineraryProducts, legProducts, components); + return Objects.hash(itineraryProducts, legProducts); } @Override @@ -188,32 +148,11 @@ public void addFareProduct(Leg leg, Collection fareProduct) { fareProduct.forEach(fp -> addFareProduct(leg, fp)); } - /** - * Convert the fare received via the deprecated {@link FareComponent} to leg products. This - * inverts the relationship: - * - fare component has several legs - * - leg product is a mapping from leg to a list of fare products - */ - @Nonnull - public Multimap legProductsFromComponents() { - Multimap legProductsFromComponents = HashMultimap.create(); - for (var type : getFareTypes()) { - var components = getComponents(type); - - for (var c : components) { - var firstLegStartTime = c.legs().get(0).getStartTime(); - for (var leg : c.legs()) { - final FareProduct fareProduct = FareProduct - .of(c.fareId(), type.name(), c.price()) - .build(); - - legProductsFromComponents.put( - leg, - new FareProductUse(fareProduct.uniqueInstanceId(firstLegStartTime), fareProduct) - ); - } - } - } - return legProductsFromComponents; + public void addFareProducts(Multimap fareProducts) { + fareProducts.forEach((leg, fp) -> addFareProduct(leg, fp)); + } + + public void addFareProductUses(Multimap fareProducts) { + legProducts.putAll(fareProducts); } } diff --git a/src/main/java/org/opentripplanner/routing/core/FareComponent.java b/src/main/java/org/opentripplanner/routing/core/FareComponent.java deleted file mode 100644 index 4c609a80f19..00000000000 --- a/src/main/java/org/opentripplanner/routing/core/FareComponent.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.opentripplanner.routing.core; - -import java.util.List; -import org.opentripplanner.model.fare.FareProduct; -import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.transit.model.basic.Money; -import org.opentripplanner.transit.model.framework.FeedScopedId; - -/** - *

- * FareComponent is a sequence of routes for a particular fare. - *

- * @deprecated Because it exists only for backwards compatibility, and you should use the Fares V2 - * type, namely {@link FareProduct}. - */ -@Deprecated -public record FareComponent(FeedScopedId fareId, Money price, List legs) { - public List routes() { - return legs.stream().map(l -> l.getRoute().getId()).toList(); - } -} diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java index a65c46b12fe..6e99e096c2c 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java @@ -61,7 +61,6 @@ import org.opentripplanner.routing.alertpatch.TimePeriod; import org.opentripplanner.routing.alertpatch.TransitAlert; import org.opentripplanner.routing.api.request.RouteRequest; -import org.opentripplanner.routing.core.FareComponent; import org.opentripplanner.routing.core.FareType; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.routing.graphfinder.GraphFinder; @@ -185,10 +184,6 @@ static void setup() { var fares = new ItineraryFares(); fares.addFare(FareType.regular, Money.euros(3.1f)); - fares.addFareComponent( - FareType.regular, - List.of(new FareComponent(id("AB"), Money.euros(3.1f), List.of(busLeg))) - ); var dayPass = fareProduct("day-pass"); fares.addItineraryProducts(List.of(dayPass)); From 673415cbae447b24503e2a65de099b4ada1efe32 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 9 Jan 2024 16:33:01 +0100 Subject: [PATCH 02/69] Update test assertion --- .../ext/fares/FaresToItineraryMapper.java | 9 +- .../__snapshots__/BikeRentalSnapshotTest.snap | 600 +++++++++--------- .../__snapshots__/ElevationSnapshotTest.snap | 300 +++++---- .../__snapshots__/TransitSnapshotTest.snap | 572 +++++++++-------- 4 files changed, 734 insertions(+), 747 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/fares/FaresToItineraryMapper.java b/src/ext/java/org/opentripplanner/ext/fares/FaresToItineraryMapper.java index f4a871b3ceb..c545cbbb858 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/FaresToItineraryMapper.java +++ b/src/ext/java/org/opentripplanner/ext/fares/FaresToItineraryMapper.java @@ -4,7 +4,6 @@ import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.fare.ItineraryFares; import org.opentripplanner.model.plan.Itinerary; -import org.opentripplanner.model.plan.Leg; /** * Takes fares and applies them to the legs of an itinerary. @@ -21,13 +20,9 @@ public static void addFaresToLegs(ItineraryFares fares, Itinerary i) { }) .toList(); - final Multimap legProductsFromComponents = fares.legProductsFromComponents(); - i.transformTransitLegs(leg -> { - var legInstances = fares.getLegProducts().get(leg); - leg.setFareProducts( - ListUtils.combine(itineraryFareUses, legProductsFromComponents.get(leg), legInstances) - ); + var legUses = fares.getLegProducts().get(leg); + leg.setFareProducts(ListUtils.combine(itineraryFareUses, legUses)); return leg; }); } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/BikeRentalSnapshotTest.snap b/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/BikeRentalSnapshotTest.snap index d99f479ac16..36c56471be1 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/BikeRentalSnapshotTest.snap +++ b/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/BikeRentalSnapshotTest.snap @@ -22,31 +22,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.accessBikeR "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "17" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -57,7 +33,29 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.accessBikeR "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 3 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2209, "legs" : [ @@ -510,31 +508,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.accessBikeR "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "20" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -545,7 +519,29 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.accessBikeR "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2539, "legs" : [ @@ -956,31 +952,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.accessBikeR "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "77" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -991,7 +963,29 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.accessBikeR "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 1805, "legs" : [ @@ -1298,31 +1292,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.accessBikeR "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "17" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -1333,7 +1303,29 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.accessBikeR "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 3 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2209, "legs" : [ @@ -1786,31 +1778,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.accessBikeR "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "17" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -1821,7 +1789,29 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.accessBikeR "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 3 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2209, "legs" : [ @@ -2274,31 +2264,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.accessBikeR "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "77" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -2309,7 +2275,29 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.accessBikeR "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 1805, "legs" : [ @@ -3291,31 +3279,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.egressBikeR "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "17" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -3326,7 +3290,29 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.egressBikeR "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2119, "legs" : [ @@ -3831,31 +3817,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.egressBikeR "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "20" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -3866,7 +3828,29 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.egressBikeR "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2503, "legs" : [ @@ -4251,31 +4235,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.egressBikeR "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "77" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -4286,7 +4246,29 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.egressBikeR "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2351, "legs" : [ @@ -4645,31 +4627,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.egressBikeR "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "17" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -4680,7 +4638,29 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.egressBikeR "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2119, "legs" : [ @@ -5185,31 +5165,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.egressBikeR "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "20" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -5220,7 +5176,29 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.egressBikeR "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2563, "legs" : [ @@ -5605,31 +5583,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.egressBikeR "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "77" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -5640,7 +5594,29 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.egressBikeR "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2351, "legs" : [ diff --git a/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/ElevationSnapshotTest.snap b/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/ElevationSnapshotTest.snap index b5e40b383e4..5baa72515ec 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/ElevationSnapshotTest.snap +++ b/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/ElevationSnapshotTest.snap @@ -550,31 +550,7 @@ org.opentripplanner.routing.algorithm.mapping.ElevationSnapshotTest.transit=[ "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "17" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -585,7 +561,29 @@ org.opentripplanner.routing.algorithm.mapping.ElevationSnapshotTest.transit=[ "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2305, "legs" : [ @@ -946,31 +944,7 @@ org.opentripplanner.routing.algorithm.mapping.ElevationSnapshotTest.transit=[ "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "20" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -981,7 +955,29 @@ org.opentripplanner.routing.algorithm.mapping.ElevationSnapshotTest.transit=[ "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2465, "legs" : [ @@ -1368,31 +1364,7 @@ org.opentripplanner.routing.algorithm.mapping.ElevationSnapshotTest.transit=[ "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "77" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -1403,7 +1375,29 @@ org.opentripplanner.routing.algorithm.mapping.ElevationSnapshotTest.transit=[ "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2396, "legs" : [ @@ -1764,31 +1758,7 @@ org.opentripplanner.routing.algorithm.mapping.ElevationSnapshotTest.transit=[ "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "15" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -1799,7 +1769,29 @@ org.opentripplanner.routing.algorithm.mapping.ElevationSnapshotTest.transit=[ "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2787, "legs" : [ @@ -2238,31 +2230,7 @@ org.opentripplanner.routing.algorithm.mapping.ElevationSnapshotTest.transit=[ "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "17" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -2273,7 +2241,29 @@ org.opentripplanner.routing.algorithm.mapping.ElevationSnapshotTest.transit=[ "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2305, "legs" : [ @@ -2634,31 +2624,7 @@ org.opentripplanner.routing.algorithm.mapping.ElevationSnapshotTest.transit=[ "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "20" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -2669,7 +2635,29 @@ org.opentripplanner.routing.algorithm.mapping.ElevationSnapshotTest.transit=[ "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2525, "legs" : [ diff --git a/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/TransitSnapshotTest.snap b/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/TransitSnapshotTest.snap index f67c75f44ec..8c36afa32e6 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/TransitSnapshotTest.snap +++ b/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/TransitSnapshotTest.snap @@ -250,31 +250,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "20" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -285,7 +261,29 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 4281, "legs" : [ @@ -735,31 +733,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "15" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -770,7 +744,29 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2315, "legs" : [ @@ -1285,31 +1281,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "20" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -1320,7 +1292,29 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 4295, "legs" : [ @@ -1770,31 +1764,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "15" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -1805,7 +1775,29 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2385, "legs" : [ @@ -2320,35 +2312,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "70" - }, - { - "feedId" : "prt", - "id" : "77" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -2359,7 +2323,49 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + }, + { + "legIndices" : [ + 2 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 3375, "legs" : [ @@ -3053,31 +3059,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "20" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -3088,7 +3070,29 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2895, "legs" : [ @@ -3541,31 +3545,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "20" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -3576,7 +3556,29 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2925, "legs" : [ @@ -4029,31 +4031,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "20" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -4064,7 +4042,29 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2895, "legs" : [ @@ -4517,35 +4517,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "70" - }, - { - "feedId" : "prt", - "id" : "77" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -4556,7 +4528,49 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + }, + { + "legIndices" : [ + 2 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 2957, "legs" : [ @@ -5029,35 +5043,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "name" : "regular" } ], - "details" : { - "regular" : [ - { - "fareId" : { - "feedId" : "prt", - "id" : "8" - }, - "price" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "routes" : [ - { - "feedId" : "prt", - "id" : "20" - }, - { - "feedId" : "prt", - "id" : "15" - } - ] - } - ] - }, + "details" : { }, "fare" : { "regular" : { "cents" : 200, @@ -5068,7 +5054,49 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan "symbol" : "$" } } - } + }, + "legProducts" : [ + { + "legIndices" : [ + 1 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + }, + { + "legIndices" : [ + 2 + ], + "products" : [ + { + "amount" : { + "cents" : 200, + "currency" : { + "currency" : "USD", + "currencyCode" : "USD", + "defaultFractionDigits" : 2, + "symbol" : "$" + } + }, + "id" : "prt:8", + "name" : "prt:8" + } + ] + } + ] }, "generalizedCost" : 3015, "legs" : [ From f5b95975e82e6e5868438249f75a8728b4ce5dbb Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 9 Jan 2024 17:26:53 +0100 Subject: [PATCH 03/69] Remove fare component tests --- .../ext/fares/impl/FaresIntegrationTest.java | 119 ------------------ .../ext/restapi/mapping/FareMapperTest.java | 2 - .../ext/fares/impl/farecomponents.gtfs.zip | Bin 2266 -> 0 bytes .../apis/gtfs/expectations/plan-fares.json | 30 +---- 4 files changed, 1 insertion(+), 150 deletions(-) delete mode 100644 src/ext-test/resources/org/opentripplanner/ext/fares/impl/farecomponents.gtfs.zip diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/impl/FaresIntegrationTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/impl/FaresIntegrationTest.java index ecf06c6b7df..d6a1432a75b 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/impl/FaresIntegrationTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/impl/FaresIntegrationTest.java @@ -22,7 +22,6 @@ import org.opentripplanner.routing.core.FareType; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.standalone.api.OtpServerRequestContext; -import org.opentripplanner.test.support.ResourceLoader; import org.opentripplanner.transit.model.basic.Money; import org.opentripplanner.transit.service.TransitModel; @@ -105,124 +104,6 @@ public void testPortland() { // assertEquals(cost.getFare(FareType.regular), new Money(new WrappedCurrency("USD"), 430)); } - @Test - public void testFareComponent() { - TestOtpModel model = ConstantsForTests.buildGtfsGraph( - ResourceLoader.of(this).file("farecomponents.gtfs.zip") - ); - Graph graph = model.graph(); - TransitModel transitModel = model.transitModel(); - String feedId = transitModel.getFeedIds().iterator().next(); - - var serverContext = TestServerContext.createServerContext(graph, transitModel); - - Money tenUSD = Money.usDollars(10); - - var dateTime = LocalDateTime - .of(2009, 8, 7, 0, 0, 0) - .atZone(ZoneId.of("America/Los_Angeles")) - .toInstant(); - - // A -> B, base case - - var from = GenericLocation.fromStopId("Origin", feedId, "A"); - var to = GenericLocation.fromStopId("Destination", feedId, "B"); - - var fare = getFare(from, to, dateTime, serverContext); - /* - var fareComponents = fare.getComponents(FareType.regular); - assertEquals(fareComponents.size(), 1); - assertEquals(fareComponents.get(0).price(), tenUSD); - assertEquals(fareComponents.get(0).fareId(), new FeedScopedId(feedId, "AB")); - assertEquals(fareComponents.get(0).routes().get(0), new FeedScopedId(feedId, "1")); - - // D -> E, null case - - from = GenericLocation.fromStopId("Origin", feedId, "D"); - to = GenericLocation.fromStopId("Destination", feedId, "E"); - fare = getFare(from, to, dateTime, serverContext); - assertEquals(ItineraryFares.empty(), fare); - - // A -> C, 2 components in a path - - from = GenericLocation.fromStopId("Origin", feedId, "A"); - to = GenericLocation.fromStopId("Destination", feedId, "C"); - fare = getFare(from, to, dateTime, serverContext); - - fareComponents = fare.getComponents(FareType.regular); - assertEquals(fareComponents.size(), 2); - assertEquals(fareComponents.get(0).price(), tenUSD); - assertEquals(fareComponents.get(0).fareId(), new FeedScopedId(feedId, "AB")); - assertEquals(fareComponents.get(0).routes().get(0), new FeedScopedId(feedId, "1")); - assertEquals(fareComponents.get(1).price(), tenUSD); - assertEquals(fareComponents.get(1).fareId(), new FeedScopedId(feedId, "BC")); - assertEquals(fareComponents.get(1).routes().get(0), new FeedScopedId(feedId, "2")); - - // B -> D, 2 fully connected components - from = GenericLocation.fromStopId("Origin", feedId, "B"); - to = GenericLocation.fromStopId("Destination", feedId, "D"); - fare = getFare(from, to, dateTime, serverContext); - - fareComponents = fare.getComponents(FareType.regular); - assertEquals(fareComponents.size(), 1); - assertEquals(fareComponents.get(0).price(), tenUSD); - assertEquals(fareComponents.get(0).fareId(), new FeedScopedId(feedId, "BD")); - assertEquals(fareComponents.get(0).routes().get(0), new FeedScopedId(feedId, "2")); - assertEquals(fareComponents.get(0).routes().get(1), new FeedScopedId(feedId, "3")); - - // E -> G, missing in between fare - from = GenericLocation.fromStopId("Origin", feedId, "E"); - to = GenericLocation.fromStopId("Destination", feedId, "G"); - fare = getFare(from, to, dateTime, serverContext); - - fareComponents = fare.getComponents(FareType.regular); - assertEquals(fareComponents.size(), 1); - assertEquals(tenUSD, fareComponents.get(0).price()); - assertEquals(fareComponents.get(0).fareId(), new FeedScopedId(feedId, "EG")); - assertEquals(fareComponents.get(0).routes().get(0), new FeedScopedId(feedId, "5")); - assertEquals(fareComponents.get(0).routes().get(1), new FeedScopedId(feedId, "6")); - - // C -> E, missing fare after - from = GenericLocation.fromStopId("Origin", feedId, "C"); - to = GenericLocation.fromStopId("Destination", feedId, "E"); - fare = getFare(from, to, dateTime, serverContext); - - fareComponents = fare.getComponents(FareType.regular); - assertEquals(fareComponents.size(), 1); - assertEquals(fareComponents.get(0).price(), tenUSD); - assertEquals(fareComponents.get(0).fareId(), new FeedScopedId(feedId, "CD")); - assertEquals(fareComponents.get(0).routes().get(0), new FeedScopedId(feedId, "3")); - - // D -> G, missing fare before - from = GenericLocation.fromStopId("Origin", feedId, "D"); - to = GenericLocation.fromStopId("Destination", feedId, "G"); - fare = getFare(from, to, dateTime, serverContext); - - fareComponents = fare.getComponents(FareType.regular); - assertEquals(fareComponents.size(), 1); - assertEquals(fareComponents.get(0).price(), tenUSD); - assertEquals(fareComponents.get(0).fareId(), new FeedScopedId(feedId, "EG")); - assertEquals(fareComponents.get(0).routes().get(0), new FeedScopedId(feedId, "5")); - assertEquals(fareComponents.get(0).routes().get(1), new FeedScopedId(feedId, "6")); - - // A -> D, use individual component parts - from = GenericLocation.fromStopId("Origin", feedId, "A"); - to = GenericLocation.fromStopId("Destination", feedId, "D"); - fare = getFare(from, to, dateTime, serverContext); - - fareComponents = fare.getComponents(FareType.regular); - assertEquals(fareComponents.size(), 2); - assertEquals(fareComponents.get(0).price(), tenUSD); - assertEquals(fareComponents.get(0).fareId(), new FeedScopedId(feedId, "AB")); - assertEquals(fareComponents.get(0).routes().get(0), new FeedScopedId(feedId, "1")); - assertEquals(fareComponents.get(1).price(), tenUSD); - assertEquals(fareComponents.get(1).fareId(), new FeedScopedId(feedId, "BD")); - assertEquals(fareComponents.get(1).routes().get(0), new FeedScopedId(feedId, "2")); - assertEquals(fareComponents.get(1).routes().get(1), new FeedScopedId(feedId, "3")); - - */ - } - private static ItineraryFares getFare( GenericLocation from, GenericLocation to, diff --git a/src/ext-test/java/org/opentripplanner/ext/restapi/mapping/FareMapperTest.java b/src/ext-test/java/org/opentripplanner/ext/restapi/mapping/FareMapperTest.java index bd1bd07aa43..4b455cce0f7 100644 --- a/src/ext-test/java/org/opentripplanner/ext/restapi/mapping/FareMapperTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/restapi/mapping/FareMapperTest.java @@ -3,7 +3,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.opentripplanner.model.plan.TestItineraryBuilder.newItinerary; -import java.util.List; import java.util.Locale; import org.junit.jupiter.api.Test; import org.opentripplanner.model.fare.ItineraryFares; @@ -29,6 +28,5 @@ public void emptyDetails() { var apiMoney = apiFare.fare().get(FareType.regular.name()); assertEquals(500, apiMoney.cents()); assertEquals("USD", apiMoney.currency().currency()); - assertEquals(List.of(), apiFare.details().get(FareType.regular.name())); } } diff --git a/src/ext-test/resources/org/opentripplanner/ext/fares/impl/farecomponents.gtfs.zip b/src/ext-test/resources/org/opentripplanner/ext/fares/impl/farecomponents.gtfs.zip deleted file mode 100644 index 4f7625f55c5c4ec6cbacf603709360eb6f4d0a7f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2266 zcmWIWW@Zs#-~d8~m@sPwD98oUTnq{fiRr0%$(4E~6(yk|ybSCU)E;=1+V>`Ys540_ zt>9*0WO>2NzyKz^ef-aQuj@JQbJ4S9!zZEQ;KVnV7Rg9#Rxvi;s%5V~mHW{3Lhmzv zp#?1)jJ>?L)_nPTxxuMwrD*3)R?C%DCx7m=>f5=}b>_*=Uv(>=ew_Hz^=1r1fHylw zLh|aHAwbuFToeFz>yL=lZcwK(GyoYqK({6*=A`DOBo@J4n^G7Mio>;`r#Esn81S%M z*n9tyqNvQDSwcQXn!-GSj_$vH#WQaQ`*F?Fk!j~zAJv5%vW`mrx^KoS_2}6pIzf9x z)_S_X<~J2N-EwTAb}7r9ZRM9{)JZa^c|4FfC@2SV@D_{PvEe``ft-bKa9h4Feew4<{-JYpc1ERWse^Ox|YY`Vs-jY z?;Fz$+7uam^(QF2%m480UTB*2Vx!}`>v|;1zpTAAPjv4ZiQPpSGAmXzCMEH;b^qGu zeQLsqPmCbv_44IOI0GF3asthhkYXHiCl50^uN<>JqncJ1Uj|2B)PIIubp8r|jGhy37wxn%a7%wj0?#h2!ChZ5`=JL4YnH%Td zy=449%=fSTj)z;H#4J~xs@peb+s-ZQTK+4=^EU3k-owAWX3vDCL%9c@)*UTynbD5M@T%k0_=hyVMGzFl%3Ds&~I|Wc{s>cp_6i%|CO_p%eK(=Djezyt(_WuXWHdKS$Q};!-C#(s%!U z6H>AJM`!=~ Date: Tue, 9 Jan 2024 18:02:37 +0100 Subject: [PATCH 04/69] Update more tests --- .../impl/CombinedInterlinedLegsFareServiceTest.java | 4 ++-- .../ext/fares/impl/DefaultFareServiceTest.java | 9 ++------- .../ext/fares/impl/HSLFareServiceTest.java | 4 ++-- .../HighestFareInFreeTransferWindowFareServiceTest.java | 2 +- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedLegsFareServiceTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedLegsFareServiceTest.java index dde40e06cef..350bae04dce 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedLegsFareServiceTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedLegsFareServiceTest.java @@ -92,14 +92,14 @@ void legFares() { var uses = List.copyOf(fare.getLegProducts().get(firstLeg)); assertEquals(1, uses.size()); - var firstLegUse = uses.get(0); + var firstLegUse = uses.getFirst(); assertEquals(tenDollars, firstLegUse.product().price()); var secondLeg = itinerary.getTransitLeg(1); uses = List.copyOf(fare.getLegProducts().get(secondLeg)); assertEquals(1, uses.size()); - var secondLegUse = uses.get(0); + var secondLegUse = uses.getFirst(); assertEquals(tenDollars, secondLegUse.product().price()); // the same far product is used for both legs as you only need to buy one diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java index c0daa7bd3c0..04836ea2b52 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java @@ -172,16 +172,11 @@ void multipleFeedsWithTransfersWithinFeed() { .build(); var result = service.calculateFares(itin); - var resultComponents = result - .getLegProducts() - .values() - .stream() - .map(r -> r.product().id()) - .toList(); + var legProducts = result.getLegProducts().values().stream().map(r -> r.product().id()).toList(); assertEquals( List.of(INSIDE_CITY_CENTER_SET.getFareAttribute().getId(), OTHER_FEED_ATTRIBUTE.getId()), - resultComponents + legProducts ); var resultPrice = result.getFare(FareType.regular); diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/impl/HSLFareServiceTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/impl/HSLFareServiceTest.java index a094a01412b..ae78a820661 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/impl/HSLFareServiceTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/impl/HSLFareServiceTest.java @@ -1,5 +1,6 @@ package org.opentripplanner.ext.fares.impl; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.opentripplanner.model.plan.TestItineraryBuilder.newItinerary; import static org.opentripplanner.transit.model._data.TransitModelForTest.FEED_ID; @@ -7,7 +8,6 @@ import java.util.LinkedList; import java.util.List; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -38,7 +38,7 @@ public void canCalculateHSLFares( Itinerary i, List expectedFareIds ) { - Assertions.assertArrayEquals( + assertArrayEquals( expectedFareIds.toArray(), fareService .calculateFares(i) diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/impl/HighestFareInFreeTransferWindowFareServiceTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/impl/HighestFareInFreeTransferWindowFareServiceTest.java index 48dd6b520c5..0e667f1b986 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/impl/HighestFareInFreeTransferWindowFareServiceTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/impl/HighestFareInFreeTransferWindowFareServiceTest.java @@ -46,7 +46,7 @@ public void canCalculateFare( assertEquals(expectedFare, fares.getFare(FareType.regular)); for (var type : fares.getFareTypes()) { - assertFalse(fares.getLegProducts().isEmpty()); + assertFalse(fares.getItineraryProducts().isEmpty()); var prices = fares .getItineraryProducts() From f2bcbb4b258e07fa71bc5a4d5b165ec1d81c39c9 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 10 Jan 2024 10:53:14 +0100 Subject: [PATCH 05/69] Fix price calculation of combined interlined legs --- .../ext/fares/impl/DefaultFareService.java | 23 +++++++------------ .../model/fare/ItineraryFares.java | 2 +- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/fares/impl/DefaultFareService.java b/src/ext/java/org/opentripplanner/ext/fares/impl/DefaultFareService.java index a39ccebe0e7..f0d957bf4ff 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/impl/DefaultFareService.java +++ b/src/ext/java/org/opentripplanner/ext/fares/impl/DefaultFareService.java @@ -148,11 +148,6 @@ public ItineraryFares calculateFares(Itinerary itinerary) { fareProducts.putAll(currentFare.getLegProducts()); fare.addFare(fareType, currentFare.getFare(fareType)); - currentFare - .getLegProducts() - .entries() - .forEach(entry -> fare.addFareProduct(entry.getKey(), entry.getValue().product())); - fares.add(currentFare.getFare(fareType)); // If all the legs are from one feed, consider itinerary products @@ -246,7 +241,7 @@ protected boolean populateFare( ) { FareSearch r = performSearch(fareType, legs, fareRules); - Multimap legProducts = LinkedHashMultimap.create(); + Multimap fareProductUses = LinkedHashMultimap.create(); int count = 0; int start = 0; int end = legs.size() - 1; @@ -263,34 +258,32 @@ protected boolean populateFare( int via = r.next[start][r.endOfComponent[start]]; float cost = r.resultTable[start][via]; FeedScopedId fareId = r.fareIds[start][via]; + var product = FareProduct + .of(fareId, fareId.toString(), Money.ofFractionalAmount(currency, cost)) + .build(); - var componentLegs = new ArrayList(); for (int i = start; i <= via; ++i) { final var leg = legs.get(i); + final var use = new FareProductUse(product.uniqueInstanceId(leg.getStartTime()), product); // if we have a leg that is combined for the purpose of fare calculation we need to // retrieve the original legs so that the fare products are assigned back to the original // legs that the combined one originally consisted of. // (remember that the combined leg only exists during fare calculation and is thrown away // afterwards to associating fare products with it will result in the API not showing any.) if (leg instanceof CombinedInterlinedTransitLeg combinedLeg) { - componentLegs.addAll(combinedLeg.originalLegs()); + combinedLeg.originalLegs().forEach(l -> fareProductUses.put(l, use)); } else { - componentLegs.add(leg); + fareProductUses.put(leg, use); } } - var product = FareProduct - .of(fareId, fareId.toString(), Money.ofFractionalAmount(currency, cost)) - .build(); - componentLegs.forEach(l -> legProducts.put(l, product)); - ++count; start = via + 1; } var amount = r.resultTable[0][legs.size() - 1]; fare.addFare(fareType, Money.ofFractionalAmount(currency, amount)); - fare.addFareProducts(legProducts); + fare.addFareProductUses(fareProductUses); return count > 0; } diff --git a/src/main/java/org/opentripplanner/model/fare/ItineraryFares.java b/src/main/java/org/opentripplanner/model/fare/ItineraryFares.java index 3443c01a062..8bb3e349b60 100644 --- a/src/main/java/org/opentripplanner/model/fare/ItineraryFares.java +++ b/src/main/java/org/opentripplanner/model/fare/ItineraryFares.java @@ -149,7 +149,7 @@ public void addFareProduct(Leg leg, Collection fareProduct) { } public void addFareProducts(Multimap fareProducts) { - fareProducts.forEach((leg, fp) -> addFareProduct(leg, fp)); + fareProducts.forEach(this::addFareProduct); } public void addFareProductUses(Multimap fareProducts) { From 55ee6fff8f0b27347b99fcc0e226548f4e15f149 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 10 Jan 2024 11:38:19 +0100 Subject: [PATCH 06/69] Update expecations for mulitple feed fares --- .../ext/fares/impl/DefaultFareServiceTest.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java index 04836ea2b52..3111b584ec8 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java @@ -172,11 +172,23 @@ void multipleFeedsWithTransfersWithinFeed() { .build(); var result = service.calculateFares(itin); - var legProducts = result.getLegProducts().values().stream().map(r -> r.product().id()).toList(); + var legProducts = result.getLegProducts(); + var firstBusLeg = itin.getTransitLeg(0); + var secondBusLeg = itin.getTransitLeg(2); + var finalBusLeg = itin.getTransitLeg(4); + + assertEquals( + "[FareProductUse[id=5d0d58f4-b97a-38db-921c-8b5fc6392b54, product=FareProduct{id: 'F2:other-feed-attribute', amount: $10.00}]]", + legProducts.get(firstBusLeg).toString() + ); + assertEquals( + "[FareProductUse[id=1d270201-412b-3b86-80f6-92ab144fa2e5, product=FareProduct{id: 'F:airport-to-city-center', amount: $10.00}]]", + legProducts.get(secondBusLeg).toString() + ); assertEquals( - List.of(INSIDE_CITY_CENTER_SET.getFareAttribute().getId(), OTHER_FEED_ATTRIBUTE.getId()), - legProducts + "[FareProductUse[id=678d201c-e839-35c3-ae7b-1bc3834da5e5, product=FareProduct{id: 'F2:other-feed-attribute', amount: $10.00}]]", + legProducts.get(finalBusLeg).toString() ); var resultPrice = result.getFare(FareType.regular); From af5d0497752cc622f2511d750427647b5ad13675 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 10 Jan 2024 12:09:11 +0100 Subject: [PATCH 07/69] Update assertions for HSL fares --- .../org/opentripplanner/ext/fares/impl/HSLFareServiceTest.java | 2 +- .../impl/HighestFareInFreeTransferWindowFareServiceTest.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/impl/HSLFareServiceTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/impl/HSLFareServiceTest.java index ae78a820661..4e1347cae16 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/impl/HSLFareServiceTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/impl/HSLFareServiceTest.java @@ -382,7 +382,7 @@ private static List createTestCases() { "Bus ride within zone A, then another one outside of HSL's area", hslFareService, A1_A2_F, - List.of(fareAttributeAB.getId()) + List.of(fareAttributeAB.getId(), fareAttributeAB.getId()) ) ); diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/impl/HighestFareInFreeTransferWindowFareServiceTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/impl/HighestFareInFreeTransferWindowFareServiceTest.java index 0e667f1b986..5664dcc765d 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/impl/HighestFareInFreeTransferWindowFareServiceTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/impl/HighestFareInFreeTransferWindowFareServiceTest.java @@ -44,10 +44,9 @@ public void canCalculateFare( ) { var fares = fareService.calculateFares(i); assertEquals(expectedFare, fares.getFare(FareType.regular)); + assertFalse(fares.getItineraryProducts().isEmpty()); for (var type : fares.getFareTypes()) { - assertFalse(fares.getItineraryProducts().isEmpty()); - var prices = fares .getItineraryProducts() .stream() From 6527828515b7902dfe4cfcb6840796abdc351795 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 10 Jan 2024 12:33:31 +0100 Subject: [PATCH 08/69] Remove 'component' from variable names --- .../ext/fares/impl/DefaultFareServiceTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java index 3111b584ec8..f306b61ee50 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java @@ -87,15 +87,15 @@ void shouldNotCombineInterlinedLegs() { assertEquals(TWENTY_DOLLARS, price); - var legProductsFromComponents = fare.getLegProducts(); + var legProducts = fare.getLegProducts(); var firstLeg = itin.getLegs().get(0); - var products = List.copyOf(legProductsFromComponents.get(firstLeg)); + var products = List.copyOf(legProducts.get(firstLeg)); assertEquals(TEN_DOLLARS, products.get(0).product().price()); var secondLeg = itin.getLegs().get(1); - products = List.copyOf(legProductsFromComponents.get(secondLeg)); + products = List.copyOf(legProducts.get(secondLeg)); assertEquals(TEN_DOLLARS, products.get(0).product().price()); assertEquals(1, fare.getItineraryProducts().size()); @@ -143,7 +143,7 @@ void multipleFeeds() { .build(); var result = service.calculateFares(itin); - var resultComponents = result + var fareProductIds = result .getLegProducts() .values() .stream() @@ -152,7 +152,7 @@ void multipleFeeds() { assertEquals( List.of(AIRPORT_TO_CITY_CENTER_SET.getFareAttribute().getId(), OTHER_FEED_ATTRIBUTE.getId()), - resultComponents + fareProductIds ); var resultPrice = result.getFare(FareType.regular); @@ -205,14 +205,14 @@ void multipleFeedsWithUnknownFareLegs() { .bus(OTHER_FEED_ROUTE, 2, T11_20, T11_32, Place.forStop(OTHER_FEED_STOP)) .build(); var result = service.calculateFares(itin); - var resultComponents = result + var resultProductIds = result .getLegProducts() .values() .stream() .map(r -> r.product().id()) .toList(); var resultPrice = result.getFare(FareType.regular); - assertEquals(List.of(OTHER_FEED_ATTRIBUTE.getId()), resultComponents); + assertEquals(List.of(OTHER_FEED_ATTRIBUTE.getId()), resultProductIds); assertEquals(Money.usDollars(-0.01f), resultPrice); } } From cc317540655a8d930698a01cad6810912b6a5991 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 10 Jan 2024 12:47:50 +0100 Subject: [PATCH 09/69] Simplify mapping code --- .../opentripplanner/ext/restapi/mapping/FareMapper.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/restapi/mapping/FareMapper.java b/src/ext/java/org/opentripplanner/ext/restapi/mapping/FareMapper.java index 7eb0d26339e..e8582607ce5 100644 --- a/src/ext/java/org/opentripplanner/ext/restapi/mapping/FareMapper.java +++ b/src/ext/java/org/opentripplanner/ext/restapi/mapping/FareMapper.java @@ -11,7 +11,6 @@ import java.util.stream.Collectors; import javax.annotation.Nullable; import org.opentripplanner.ext.restapi.model.ApiCurrency; -import org.opentripplanner.ext.restapi.model.ApiFareComponent; import org.opentripplanner.ext.restapi.model.ApiFareProduct; import org.opentripplanner.ext.restapi.model.ApiFareQualifier; import org.opentripplanner.ext.restapi.model.ApiItineraryFares; @@ -37,11 +36,10 @@ public FareMapper(Locale locale) { public ApiItineraryFares mapFare(Itinerary itinerary) { var fares = itinerary.getFares(); Map apiFare = toApiMoneys(fares); - Map> apiComponent = toApiFareComponents(fares); return new ApiItineraryFares( apiFare, - apiComponent, + Map.of(), toApiFareProducts(fares.getItineraryProducts()), toApiLegProducts(itinerary, fares.getLegProducts()) ); @@ -104,10 +102,6 @@ private List toApiFareProducts(Collection product) } } - private Map> toApiFareComponents(ItineraryFares fare) { - return Map.of(); - } - private Map toApiMoneys(ItineraryFares fare) { return fare .getFareTypes() From 8c14a6fd6cbf4939be58f41dc61dbd426a84caca Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 10 Jan 2024 14:35:10 +0100 Subject: [PATCH 10/69] Clean up --- .../org/opentripplanner/ext/fares/impl/OrcaFareService.java | 4 ---- .../org/opentripplanner/ext/fares/impl/OrcaFaresData.java | 2 -- .../java/org/opentripplanner/model/fare/ItineraryFares.java | 4 ---- 3 files changed, 10 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 42736472767..4879d858e86 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java +++ b/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFareService.java @@ -23,13 +23,9 @@ import org.opentripplanner.transit.model.basic.Money; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.network.Route; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class OrcaFareService extends DefaultFareService { - private static final Logger LOG = LoggerFactory.getLogger(OrcaFareService.class); - private static final Duration MAX_TRANSFER_DISCOUNT_DURATION = Duration.ofHours(2); public static final String COMM_TRANS_AGENCY_ID = "29"; diff --git a/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFaresData.java b/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFaresData.java index e970cb51718..acef59a7c03 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFaresData.java +++ b/src/ext/java/org/opentripplanner/ext/fares/impl/OrcaFaresData.java @@ -1,7 +1,5 @@ package org.opentripplanner.ext.fares.impl; -import static org.opentripplanner.transit.model.basic.Money.USD; - import java.util.Map; import org.opentripplanner.routing.core.FareType; import org.opentripplanner.transit.model.basic.Money; diff --git a/src/main/java/org/opentripplanner/model/fare/ItineraryFares.java b/src/main/java/org/opentripplanner/model/fare/ItineraryFares.java index 8bb3e349b60..80af574636a 100644 --- a/src/main/java/org/opentripplanner/model/fare/ItineraryFares.java +++ b/src/main/java/org/opentripplanner/model/fare/ItineraryFares.java @@ -148,10 +148,6 @@ public void addFareProduct(Leg leg, Collection fareProduct) { fareProduct.forEach(fp -> addFareProduct(leg, fp)); } - public void addFareProducts(Multimap fareProducts) { - fareProducts.forEach(this::addFareProduct); - } - public void addFareProductUses(Multimap fareProducts) { legProducts.putAll(fareProducts); } From 8af89a0d21f558bacdf16dab488b68a4082d2611 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 15 Jan 2024 13:08:25 +0100 Subject: [PATCH 11/69] Fix leg based fares --- .../fares/impl/DefaultFareServiceTest.java | 40 ++++++++++++++--- .../ext/fares/impl/FareModelForTest.java | 44 +++++++++++++------ .../ext/fares/impl/DefaultFareService.java | 18 ++++++-- .../ext/fares/model/FareRuleSet.java | 22 ++-------- .../model/fare/ItineraryFares.java | 1 + .../__snapshots__/BikeRentalSnapshotTest.snap | 24 +++++----- .../__snapshots__/ElevationSnapshotTest.snap | 12 ++--- .../__snapshots__/TransitSnapshotTest.snap | 26 +++++------ 8 files changed, 115 insertions(+), 72 deletions(-) diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java index f306b61ee50..c5e26cc3c9b 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/impl/DefaultFareServiceTest.java @@ -7,6 +7,8 @@ import static org.opentripplanner.ext.fares.impl.FareModelForTest.AIRPORT_TO_CITY_CENTER_SET; import static org.opentripplanner.ext.fares.impl.FareModelForTest.CITY_CENTER_A_STOP; import static org.opentripplanner.ext.fares.impl.FareModelForTest.CITY_CENTER_B_STOP; +import static org.opentripplanner.ext.fares.impl.FareModelForTest.CITY_CENTER_C_STOP; +import static org.opentripplanner.ext.fares.impl.FareModelForTest.FREE_TRANSFERS_IN_CITY_SET; import static org.opentripplanner.ext.fares.impl.FareModelForTest.INSIDE_CITY_CENTER_SET; import static org.opentripplanner.ext.fares.impl.FareModelForTest.OTHER_FEED_ATTRIBUTE; import static org.opentripplanner.ext.fares.impl.FareModelForTest.OTHER_FEED_ROUTE; @@ -61,6 +63,34 @@ void simpleZoneBasedFare() { assertEquals(TEN_DOLLARS, product.price()); } + @Test + void applyToSeveralLegs() { + var service = new DefaultFareService(); + service.addFareRules(FareType.regular, List.of(FREE_TRANSFERS_IN_CITY_SET)); + var itin = newItinerary(Place.forStop(CITY_CENTER_A_STOP), T11_00) + .bus(1, T11_00, T11_12, Place.forStop(CITY_CENTER_B_STOP)) + .bus(1, T11_16, T11_20, Place.forStop(CITY_CENTER_C_STOP)) + .build(); + + var fare = service.calculateFares(itin); + assertNotNull(fare); + + var legProducts = fare.getLegProducts(); + + var firstLeg = itin.getTransitLeg(0); + var secondLeg = itin.getTransitLeg(1); + + var firstProducts = legProducts.get(firstLeg); + var secondProducts = legProducts.get(secondLeg); + + assertEquals(firstProducts, secondProducts); + + assertEquals( + "[FareProductUse[id=ddbf1572-18bc-3724-8b64-e1c7d5c8b6c6, product=FareProduct{id: 'F:free-transfers', amount: $20.00}]]", + firstProducts.toString() + ); + } + @Test void shouldNotCombineInterlinedLegs() { var service = new DefaultFareService(); @@ -89,17 +119,17 @@ void shouldNotCombineInterlinedLegs() { var legProducts = fare.getLegProducts(); - var firstLeg = itin.getLegs().get(0); + var firstLeg = itin.getLegs().getFirst(); var products = List.copyOf(legProducts.get(firstLeg)); - assertEquals(TEN_DOLLARS, products.get(0).product().price()); + assertEquals(TEN_DOLLARS, products.getFirst().product().price()); var secondLeg = itin.getLegs().get(1); products = List.copyOf(legProducts.get(secondLeg)); - assertEquals(TEN_DOLLARS, products.get(0).product().price()); + assertEquals(TEN_DOLLARS, products.getFirst().product().price()); assertEquals(1, fare.getItineraryProducts().size()); - assertEquals(TWENTY_DOLLARS, fare.getItineraryProducts().get(0).price()); + assertEquals(TWENTY_DOLLARS, fare.getItineraryProducts().getFirst().price()); } @Test @@ -187,7 +217,7 @@ void multipleFeedsWithTransfersWithinFeed() { legProducts.get(secondBusLeg).toString() ); assertEquals( - "[FareProductUse[id=678d201c-e839-35c3-ae7b-1bc3834da5e5, product=FareProduct{id: 'F2:other-feed-attribute', amount: $10.00}]]", + "[FareProductUse[id=5d0d58f4-b97a-38db-921c-8b5fc6392b54, product=FareProduct{id: 'F2:other-feed-attribute', amount: $10.00}]]", legProducts.get(finalBusLeg).toString() ); diff --git a/src/ext-test/java/org/opentripplanner/ext/fares/impl/FareModelForTest.java b/src/ext-test/java/org/opentripplanner/ext/fares/impl/FareModelForTest.java index 200220587a6..e498588d00f 100644 --- a/src/ext-test/java/org/opentripplanner/ext/fares/impl/FareModelForTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/fares/impl/FareModelForTest.java @@ -6,6 +6,7 @@ import org.opentripplanner.ext.fares.model.FareAttribute; import org.opentripplanner.ext.fares.model.FareRuleSet; import org.opentripplanner.framework.geometry.WgsCoordinate; +import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.framework.i18n.NonLocalizedString; import org.opentripplanner.transit.model.basic.Money; import org.opentripplanner.transit.model.basic.TransitMode; @@ -27,44 +28,56 @@ public class FareModelForTest { private static final StopModelBuilder STOP_MODEL_BUILDER = StopModel.of(); - static RegularStop AIRPORT_STOP = STOP_MODEL_BUILDER + static final RegularStop AIRPORT_STOP = STOP_MODEL_BUILDER .regularStop(id("airport")) .withCoordinate(new WgsCoordinate(1, 1)) .addFareZones(AIRPORT_ZONE) - .withName(new NonLocalizedString("Airport")) + .withName(I18NString.of("Airport")) .build(); - static RegularStop CITY_CENTER_A_STOP = STOP_MODEL_BUILDER + static final RegularStop CITY_CENTER_A_STOP = STOP_MODEL_BUILDER .regularStop(id("city-center-a")) .withCoordinate(new WgsCoordinate(1, 2)) .addFareZones(CITY_CENTER_ZONE) - .withName(new NonLocalizedString("City center: stop A")) + .withName(I18NString.of("City center: stop A")) .build(); - static RegularStop CITY_CENTER_B_STOP = STOP_MODEL_BUILDER + static final RegularStop CITY_CENTER_B_STOP = STOP_MODEL_BUILDER .regularStop(id("city-center-b")) .withCoordinate(new WgsCoordinate(1, 3)) .addFareZones(CITY_CENTER_ZONE) - .withName(new NonLocalizedString("City center: stop B")) + .withName(I18NString.of("City center: stop B")) .build(); - static RegularStop SUBURB_STOP = STOP_MODEL_BUILDER + static final RegularStop CITY_CENTER_C_STOP = STOP_MODEL_BUILDER + .regularStop(id("city-center-c")) + .withCoordinate(new WgsCoordinate(1, 4)) + .addFareZones(CITY_CENTER_ZONE) + .withName(I18NString.of("City center: stop C")) + .build(); + static final RegularStop SUBURB_STOP = STOP_MODEL_BUILDER .regularStop(id("suburb")) .withCoordinate(new WgsCoordinate(1, 4)) - .withName(new NonLocalizedString("Suburb")) + .withName(I18NString.of("Suburb")) .build(); - static RegularStop OTHER_FEED_STOP = STOP_MODEL_BUILDER + static final RegularStop OTHER_FEED_STOP = STOP_MODEL_BUILDER .regularStop(FeedScopedId.ofNullable("F2", "other-feed-stop")) .withCoordinate(new WgsCoordinate(1, 5)) - .withName(new NonLocalizedString("Other feed stop")) + .withName(I18NString.of("Other feed stop")) .addFareZones(OTHER_FEED_ZONE) .build(); - static FareAttribute TEN_DOLLARS = FareAttribute + static final FareAttribute TEN_DOLLARS = FareAttribute .of(id("airport-to-city-center")) .setPrice(Money.usDollars(10)) .setTransfers(0) .build(); - static FareAttribute OTHER_FEED_ATTRIBUTE = FareAttribute + static final FareAttribute FREE_TRANSFERS = FareAttribute + .of(id("free-transfers")) + .setPrice(Money.usDollars(20)) + .setTransfers(10) + .build(); + + static final FareAttribute OTHER_FEED_ATTRIBUTE = FareAttribute .of(FeedScopedId.ofNullable("F2", "other-feed-attribute")) .setPrice(Money.usDollars(10)) .setTransfers(1) @@ -74,6 +87,7 @@ public class FareModelForTest { // Fare rule sets static FareRuleSet AIRPORT_TO_CITY_CENTER_SET = new FareRuleSet(TEN_DOLLARS); static FareRuleSet INSIDE_CITY_CENTER_SET = new FareRuleSet(TEN_DOLLARS); + static FareRuleSet FREE_TRANSFERS_IN_CITY_SET = new FareRuleSet(FREE_TRANSFERS); static FareRuleSet OTHER_FEED_SET = new FareRuleSet(OTHER_FEED_ATTRIBUTE); @@ -82,6 +96,10 @@ public class FareModelForTest { AIRPORT_ZONE.getId().getId(), CITY_CENTER_ZONE.getId().getId() ); + FREE_TRANSFERS_IN_CITY_SET.addOriginDestination( + CITY_CENTER_ZONE.getId().getId(), + CITY_CENTER_ZONE.getId().getId() + ); INSIDE_CITY_CENTER_SET.addOriginDestination( CITY_CENTER_ZONE.getId().getId(), CITY_CENTER_ZONE.getId().getId() @@ -95,7 +113,7 @@ public class FareModelForTest { static Route OTHER_FEED_ROUTE = Route .of(new FeedScopedId("F2", "other-feed-route")) .withAgency(OTHER_FEED_AGENCY) - .withLongName(new NonLocalizedString("other-feed-route")) + .withLongName(I18NString.of("other-feed-route")) .withMode(TransitMode.BUS) .build(); } diff --git a/src/ext/java/org/opentripplanner/ext/fares/impl/DefaultFareService.java b/src/ext/java/org/opentripplanner/ext/fares/impl/DefaultFareService.java index f0d957bf4ff..0bc4408b635 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/impl/DefaultFareService.java +++ b/src/ext/java/org/opentripplanner/ext/fares/impl/DefaultFareService.java @@ -259,24 +259,34 @@ protected boolean populateFare( float cost = r.resultTable[start][via]; FeedScopedId fareId = r.fareIds[start][via]; var product = FareProduct - .of(fareId, fareId.toString(), Money.ofFractionalAmount(currency, cost)) + .of(fareId, fareType.name(), Money.ofFractionalAmount(currency, cost)) .build(); + List applicableLegs = new ArrayList<>(); for (int i = start; i <= via; ++i) { final var leg = legs.get(i); - final var use = new FareProductUse(product.uniqueInstanceId(leg.getStartTime()), product); // if we have a leg that is combined for the purpose of fare calculation we need to // retrieve the original legs so that the fare products are assigned back to the original // legs that the combined one originally consisted of. // (remember that the combined leg only exists during fare calculation and is thrown away // afterwards to associating fare products with it will result in the API not showing any.) if (leg instanceof CombinedInterlinedTransitLeg combinedLeg) { - combinedLeg.originalLegs().forEach(l -> fareProductUses.put(l, use)); + applicableLegs.addAll(combinedLeg.originalLegs()); } else { - fareProductUses.put(leg, use); + applicableLegs.add(leg); } } + if (!applicableLegs.isEmpty()) { + final var use = new FareProductUse( + product.uniqueInstanceId(applicableLegs.getFirst().getStartTime()), + product + ); + applicableLegs.forEach(leg -> { + fareProductUses.put(leg, use); + }); + } + ++count; start = via + 1; } diff --git a/src/ext/java/org/opentripplanner/ext/fares/model/FareRuleSet.java b/src/ext/java/org/opentripplanner/ext/fares/model/FareRuleSet.java index 61e813e6ea4..30119631216 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/model/FareRuleSet.java +++ b/src/ext/java/org/opentripplanner/ext/fares/model/FareRuleSet.java @@ -15,7 +15,6 @@ public class FareRuleSet implements Serializable { private final Set routeOriginDestinations; private final Set contains; private final FareAttribute fareAttribute; - private final Set trips; public FareRuleSet(FareAttribute fareAttribute) { this.fareAttribute = fareAttribute; @@ -23,7 +22,6 @@ public FareRuleSet(FareAttribute fareAttribute) { originDestinations = new HashSet<>(); routeOriginDestinations = new HashSet<>(); contains = new HashSet<>(); - trips = new HashSet<>(); } public void addOriginDestination(String origin, String destination) { @@ -62,14 +60,6 @@ public FareAttribute getFareAttribute() { return fareAttribute; } - public void addTrip(FeedScopedId trip) { - trips.add(trip); - } - - public Set getTrips() { - return trips; - } - public boolean matches( String startZone, String endZone, @@ -81,7 +71,7 @@ public boolean matches( Duration journeyTime ) { //check for matching origin/destination, if this ruleset has any origin/destination restrictions - if (originDestinations.size() > 0) { + if (!originDestinations.isEmpty()) { var od = new OriginDestination(startZone, endZone); if (!originDestinations.contains(od)) { var od2 = new OriginDestination(od.origin, null); @@ -95,25 +85,19 @@ public boolean matches( } //check for matching contains, if this ruleset has any containment restrictions - if (contains.size() > 0) { + if (!contains.isEmpty()) { if (!zonesVisited.equals(contains)) { return false; } } //check for matching routes - if (routes.size() != 0) { + if (!routes.isEmpty()) { if (!routes.containsAll(routesVisited)) { return false; } } - //check for matching trips - if (trips.size() != 0) { - if (!trips.containsAll(tripsVisited)) { - return false; - } - } if (fareAttribute.isTransfersSet() && fareAttribute.getTransfers() < transfersUsed) { return false; } diff --git a/src/main/java/org/opentripplanner/model/fare/ItineraryFares.java b/src/main/java/org/opentripplanner/model/fare/ItineraryFares.java index 80af574636a..d60dbfb249e 100644 --- a/src/main/java/org/opentripplanner/model/fare/ItineraryFares.java +++ b/src/main/java/org/opentripplanner/model/fare/ItineraryFares.java @@ -94,6 +94,7 @@ public void addItineraryProducts(Collection products) { * instead. */ @Nullable + @Deprecated public Money getFare(FareType type) { return fares.get(type); } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/BikeRentalSnapshotTest.snap b/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/BikeRentalSnapshotTest.snap index 36c56471be1..41bc4278ca1 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/BikeRentalSnapshotTest.snap +++ b/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/BikeRentalSnapshotTest.snap @@ -51,7 +51,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.accessBikeR } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -537,7 +537,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.accessBikeR } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -981,7 +981,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.accessBikeR } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -1321,7 +1321,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.accessBikeR } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -1807,7 +1807,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.accessBikeR } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -2293,7 +2293,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.accessBikeR } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -3308,7 +3308,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.egressBikeR } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -3846,7 +3846,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.egressBikeR } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -4264,7 +4264,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.egressBikeR } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -4656,7 +4656,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.egressBikeR } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -5194,7 +5194,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.egressBikeR } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -5612,7 +5612,7 @@ org.opentripplanner.routing.algorithm.mapping.BikeRentalSnapshotTest.egressBikeR } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/ElevationSnapshotTest.snap b/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/ElevationSnapshotTest.snap index 5baa72515ec..6579e4bbd37 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/ElevationSnapshotTest.snap +++ b/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/ElevationSnapshotTest.snap @@ -579,7 +579,7 @@ org.opentripplanner.routing.algorithm.mapping.ElevationSnapshotTest.transit=[ } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -973,7 +973,7 @@ org.opentripplanner.routing.algorithm.mapping.ElevationSnapshotTest.transit=[ } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -1393,7 +1393,7 @@ org.opentripplanner.routing.algorithm.mapping.ElevationSnapshotTest.transit=[ } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -1787,7 +1787,7 @@ org.opentripplanner.routing.algorithm.mapping.ElevationSnapshotTest.transit=[ } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -2259,7 +2259,7 @@ org.opentripplanner.routing.algorithm.mapping.ElevationSnapshotTest.transit=[ } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -2653,7 +2653,7 @@ org.opentripplanner.routing.algorithm.mapping.ElevationSnapshotTest.transit=[ } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/TransitSnapshotTest.snap b/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/TransitSnapshotTest.snap index 8c36afa32e6..d5da342f9a6 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/TransitSnapshotTest.snap +++ b/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/TransitSnapshotTest.snap @@ -279,7 +279,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -762,7 +762,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -1310,7 +1310,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -1793,7 +1793,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -2341,7 +2341,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] }, @@ -2361,7 +2361,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -3088,7 +3088,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -3574,7 +3574,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -4060,7 +4060,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -4546,7 +4546,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] }, @@ -4566,7 +4566,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } @@ -5072,7 +5072,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] }, @@ -5092,7 +5092,7 @@ org.opentripplanner.routing.algorithm.mapping.TransitSnapshotTest.test_trip_plan } }, "id" : "prt:8", - "name" : "prt:8" + "name" : "regular" } ] } From 5a4cb9a67023fb0eadf556d98004d3e620ed6c8f Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 16 Jan 2024 14:08:01 +0100 Subject: [PATCH 12/69] Introduce extra layer for vector tiles config --- docs/RouterConfiguration.md | 108 +++++------ docs/sandbox/MapboxVectorTilesApi.md | 176 +++++++++--------- .../standalone/config/RouterConfig.java | 9 +- .../config/routerconfig/VectorTileConfig.java | 32 +++- .../configure/ConstructApplicationModule.java | 2 +- .../server/DefaultServerRequestContext.java | 13 +- .../opentripplanner/TestServerContext.java | 2 +- .../mapping/TripRequestMapperTest.java | 2 +- .../doc/RouterConfigurationDocTest.java | 2 +- .../transit/speed_test/SpeedTest.java | 3 +- .../standalone/config/router-config.json | 146 ++++++++------- 11 files changed, 267 insertions(+), 228 deletions(-) diff --git a/docs/RouterConfiguration.md b/docs/RouterConfiguration.md index 5ca87a2aefa..351c582d72d 100644 --- a/docs/RouterConfiguration.md +++ b/docs/RouterConfiguration.md @@ -67,7 +67,7 @@ A full list of them can be found in the [RouteRequest](RouteRequest.md). |    [hideFeedId](#transmodelApi_hideFeedId) | `boolean` | Hide the FeedId in all API output, and add it to input. | *Optional* | `false` | na | |    [tracingHeaderTags](#transmodelApi_tracingHeaderTags) | `string[]` | Used to group requests when monitoring OTP. | *Optional* | | na | | [updaters](UpdaterConfig.md) | `object[]` | Configuration for the updaters that import various types of data into OTP. | *Optional* | | 1.5 | -| [vectorTileLayers](sandbox/MapboxVectorTilesApi.md) | `object[]` | Configuration of the individual layers for the Mapbox vector tiles. | *Optional* | | 2.0 | +| [vectorTiles](sandbox/MapboxVectorTilesApi.md) | `object` | TODO: Add short summary. | *Optional* | | na | | [vehicleRentalServiceDirectory](sandbox/VehicleRentalServiceDirectory.md) | `object` | Configuration for the vehicle rental service directory. | *Optional* | | 2.0 | @@ -602,58 +602,60 @@ Used to group requests when monitoring OTP. "transmodelApi" : { "hideFeedId" : true }, - "vectorTileLayers" : [ - { - "name" : "stops", - "type" : "Stop", - "mapper" : "Digitransit", - "maxZoom" : 20, - "minZoom" : 14, - "cacheMaxSeconds" : 600 - }, - { - "name" : "stations", - "type" : "Station", - "mapper" : "Digitransit", - "maxZoom" : 20, - "minZoom" : 12, - "cacheMaxSeconds" : 600 - }, - { - "name" : "rentalPlaces", - "type" : "VehicleRental", - "mapper" : "Digitransit", - "maxZoom" : 20, - "minZoom" : 14, - "cacheMaxSeconds" : 60, - "expansionFactor" : 0.25 - }, - { - "name" : "rentalVehicle", - "type" : "VehicleRentalVehicle", - "mapper" : "Digitransit", - "maxZoom" : 20, - "minZoom" : 14, - "cacheMaxSeconds" : 60 - }, - { - "name" : "rentalStation", - "type" : "VehicleRentalStation", - "mapper" : "Digitransit", - "maxZoom" : 20, - "minZoom" : 14, - "cacheMaxSeconds" : 600 - }, - { - "name" : "vehicleParking", - "type" : "VehicleParking", - "mapper" : "Digitransit", - "maxZoom" : 20, - "minZoom" : 14, - "cacheMaxSeconds" : 60, - "expansionFactor" : 0.25 - } - ], + "vectorTiles" : { + "layers" : [ + { + "name" : "stops", + "type" : "Stop", + "mapper" : "Digitransit", + "maxZoom" : 20, + "minZoom" : 14, + "cacheMaxSeconds" : 600 + }, + { + "name" : "stations", + "type" : "Station", + "mapper" : "Digitransit", + "maxZoom" : 20, + "minZoom" : 12, + "cacheMaxSeconds" : 600 + }, + { + "name" : "rentalPlaces", + "type" : "VehicleRental", + "mapper" : "Digitransit", + "maxZoom" : 20, + "minZoom" : 14, + "cacheMaxSeconds" : 60, + "expansionFactor" : 0.25 + }, + { + "name" : "rentalVehicle", + "type" : "VehicleRentalVehicle", + "mapper" : "Digitransit", + "maxZoom" : 20, + "minZoom" : 14, + "cacheMaxSeconds" : 60 + }, + { + "name" : "rentalStation", + "type" : "VehicleRentalStation", + "mapper" : "Digitransit", + "maxZoom" : 20, + "minZoom" : 14, + "cacheMaxSeconds" : 600 + }, + { + "name" : "vehicleParking", + "type" : "VehicleParking", + "mapper" : "Digitransit", + "maxZoom" : 20, + "minZoom" : 14, + "cacheMaxSeconds" : 60, + "expansionFactor" : 0.25 + } + ] + }, "timetableUpdates" : { "purgeExpiredData" : false, "maxSnapshotFrequency" : "2s" diff --git a/docs/sandbox/MapboxVectorTilesApi.md b/docs/sandbox/MapboxVectorTilesApi.md index 8ef8ee179e7..0904bd1fef6 100644 --- a/docs/sandbox/MapboxVectorTilesApi.md +++ b/docs/sandbox/MapboxVectorTilesApi.md @@ -35,93 +35,95 @@ The feature must be configured in `router-config.json` as follows ```JSON { - "vectorTileLayers": [ - { - "name": "stops", - "type": "Stop", - "mapper": "Digitransit", - "maxZoom": 20, - "minZoom": 14, - "cacheMaxSeconds": 600 - }, - { - "name": "stations", - "type": "Station", - "mapper": "Digitransit", - "maxZoom": 20, - "minZoom": 12, - "cacheMaxSeconds": 600 - }, - // all rental places: stations and free-floating vehicles - { - "name": "citybikes", - "type": "VehicleRental", - "mapper": "Digitransit", - "maxZoom": 20, - "minZoom": 14, - "cacheMaxSeconds": 60, - "expansionFactor": 0.25 - }, - // just free-floating vehicles - { - "name": "rentalVehicles", - "type": "VehicleRentalVehicle", - "mapper": "DigitransitRealtime", - "maxZoom": 20, - "minZoom": 14, - "cacheMaxSeconds": 60 - }, - // just rental stations - { - "name": "rentalStations", - "type": "VehicleRentalStation", - "mapper": "Digitransit", - "maxZoom": 20, - "minZoom": 14, - "cacheMaxSeconds": 600 - }, - // Contains just stations and real-time information for them - { - "name": "realtimeRentalStations", - "type": "VehicleRentalStation", - "mapper": "DigitransitRealtime", - "maxZoom": 20, - "minZoom": 14, - "cacheMaxSeconds": 60 - }, - // This exists for backwards compatibility. At some point, we might want - // to add a new real-time parking mapper with better translation support - // and less unnecessary fields. - { - "name": "stadtnaviVehicleParking", - "type": "VehicleParking", - "mapper": "Stadtnavi", - "maxZoom": 20, - "minZoom": 14, - "cacheMaxSeconds": 60, - "expansionFactor": 0.25 - }, - // no real-time, translatable fields are translated based on accept-language header - // and contains less fields than the Stadtnavi mapper - { - "name": "vehicleParking", - "type": "VehicleParking", - "mapper": "Digitransit", - "maxZoom": 20, - "minZoom": 14, - "cacheMaxSeconds": 600, - "expansionFactor": 0.25 - }, - { - "name": "vehicleParkingGroups", - "type": "VehicleParkingGroup", - "mapper": "Digitransit", - "maxZoom": 17, - "minZoom": 14, - "cacheMaxSeconds": 600, - "expansionFactor": 0.25 - } - ] + "vectorTiles": + "layers": [ + { + "name": "stops", + "type": "Stop", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 600 + }, + { + "name": "stations", + "type": "Station", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 12, + "cacheMaxSeconds": 600 + }, + // all rental places: stations and free-floating vehicles + { + "name": "citybikes", + "type": "VehicleRental", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 60, + "expansionFactor": 0.25 + }, + // just free-floating vehicles + { + "name": "rentalVehicles", + "type": "VehicleRentalVehicle", + "mapper": "DigitransitRealtime", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 60 + }, + // just rental stations + { + "name": "rentalStations", + "type": "VehicleRentalStation", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 600 + }, + // Contains just stations and real-time information for them + { + "name": "realtimeRentalStations", + "type": "VehicleRentalStation", + "mapper": "DigitransitRealtime", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 60 + }, + // This exists for backwards compatibility. At some point, we might want + // to add a new real-time parking mapper with better translation support + // and less unnecessary fields. + { + "name": "stadtnaviVehicleParking", + "type": "VehicleParking", + "mapper": "Stadtnavi", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 60, + "expansionFactor": 0.25 + }, + // no real-time, translatable fields are translated based on accept-language header + // and contains less fields than the Stadtnavi mapper + { + "name": "vehicleParking", + "type": "VehicleParking", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 600, + "expansionFactor": 0.25 + }, + { + "name": "vehicleParkingGroups", + "type": "VehicleParkingGroup", + "mapper": "Digitransit", + "maxZoom": 17, + "minZoom": 14, + "cacheMaxSeconds": 600, + "expansionFactor": 0.25 + } + ] + } } ``` diff --git a/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java b/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java index ae92486037d..bf97155b747 100644 --- a/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/RouterConfig.java @@ -9,7 +9,6 @@ import java.io.Serializable; import java.util.List; import org.opentripplanner.ext.ridehailing.RideHailingServiceParameters; -import org.opentripplanner.ext.vectortiles.VectorTilesResource; import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.standalone.config.framework.json.NodeAdapter; import org.opentripplanner.standalone.config.routerconfig.RideHailingServicesConfig; @@ -48,7 +47,7 @@ public class RouterConfig implements Serializable { private final RideHailingServicesConfig rideHailingConfig; private final FlexConfig flexConfig; private final TransmodelAPIConfig transmodelApi; - private final VectorTileConfig vectorTileLayers; + private final VectorTileConfig vectorTileConfig; public RouterConfig(JsonNode node, String source, boolean logUnusedParams) { this(new NodeAdapter(node, source), logUnusedParams); @@ -72,7 +71,7 @@ public RouterConfig(JsonNode node, String source, boolean logUnusedParams) { this.routingRequestDefaults.setMaxSearchWindow(transitConfig.maxSearchWindow()); this.updatersParameters = new UpdatersConfig(root); this.rideHailingConfig = new RideHailingServicesConfig(root); - this.vectorTileLayers = VectorTileConfig.mapVectorTilesParameters(root, "vectorTileLayers"); + this.vectorTileConfig = VectorTileConfig.mapVectorTilesParameters(root, "vectorTiles"); this.flexConfig = new FlexConfig(root, "flex"); if (logUnusedParams && LOG.isWarnEnabled()) { @@ -124,8 +123,8 @@ public List rideHailingServiceParameters() { return rideHailingConfig.rideHailingServiceParameters(); } - public VectorTilesResource.LayersParameters vectorTileLayers() { - return vectorTileLayers; + public VectorTileConfig vectorTileConfig() { + return vectorTileConfig; } public FlexConfig flexConfig() { diff --git a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java index a0342910be9..b3b48e19c23 100644 --- a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java @@ -5,22 +5,32 @@ import static org.opentripplanner.inspector.vector.LayerParameters.MAX_ZOOM; import static org.opentripplanner.inspector.vector.LayerParameters.MIN_ZOOM; import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_0; +import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_1; +import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_5; import java.util.Collection; import java.util.List; +import javax.annotation.Nullable; import org.opentripplanner.ext.vectortiles.VectorTilesResource; import org.opentripplanner.inspector.vector.LayerParameters; import org.opentripplanner.standalone.config.framework.json.NodeAdapter; +import org.opentripplanner.standalone.config.framework.json.ParameterBuilder; public class VectorTileConfig implements VectorTilesResource.LayersParameters { - List> layers; + public static final VectorTileConfig DEFAULT = new VectorTileConfig(List.of(), null); + private final List> layers; - public VectorTileConfig( - Collection> layers + @Nullable + private final String basePath; + + VectorTileConfig( + Collection> layers, + @Nullable String basePath ) { this.layers = List.copyOf(layers); + this.basePath = basePath; } @Override @@ -28,16 +38,20 @@ public List> layers() { return layers; } - public static VectorTileConfig mapVectorTilesParameters( - NodeAdapter root, - String vectorTileLayers - ) { + @Nullable + public String basePath() { + return basePath; + } + + public static VectorTileConfig mapVectorTilesParameters(NodeAdapter node, String paramName) { + var root = node.of(paramName).asObject(); return new VectorTileConfig( root - .of(vectorTileLayers) + .of("layers") .since(V2_0) .summary("Configuration of the individual layers for the Mapbox vector tiles.") - .asObjects(VectorTileConfig::mapLayer) + .asObjects(VectorTileConfig::mapLayer), + root.of("basePath").since(V2_5).asString(null) ); } diff --git a/src/main/java/org/opentripplanner/standalone/configure/ConstructApplicationModule.java b/src/main/java/org/opentripplanner/standalone/configure/ConstructApplicationModule.java index c9d7253b0be..5d8efcd3a5b 100644 --- a/src/main/java/org/opentripplanner/standalone/configure/ConstructApplicationModule.java +++ b/src/main/java/org/opentripplanner/standalone/configure/ConstructApplicationModule.java @@ -49,7 +49,7 @@ OtpServerRequestContext providesServerContext( graph, transitService, Metrics.globalRegistry, - routerConfig.vectorTileLayers(), + routerConfig.vectorTileConfig(), worldEnvelopeService, realtimeVehicleService, vehicleRentalService, diff --git a/src/main/java/org/opentripplanner/standalone/server/DefaultServerRequestContext.java b/src/main/java/org/opentripplanner/standalone/server/DefaultServerRequestContext.java index f14fea66693..c0ac70309e6 100644 --- a/src/main/java/org/opentripplanner/standalone/server/DefaultServerRequestContext.java +++ b/src/main/java/org/opentripplanner/standalone/server/DefaultServerRequestContext.java @@ -24,6 +24,7 @@ import org.opentripplanner.standalone.api.HttpRequestScoped; import org.opentripplanner.standalone.api.OtpServerRequestContext; import org.opentripplanner.standalone.config.routerconfig.TransitRoutingConfig; +import org.opentripplanner.standalone.config.routerconfig.VectorTileConfig; import org.opentripplanner.standalone.config.sandbox.FlexConfig; import org.opentripplanner.transit.service.TransitService; @@ -39,7 +40,7 @@ public class DefaultServerRequestContext implements OtpServerRequestContext { private final MeterRegistry meterRegistry; private final RaptorConfig raptorConfig; private final TileRendererManager tileRendererManager; - private final VectorTilesResource.LayersParameters vectorTileLayers; + private final VectorTileConfig vectorTileConfig; private final FlexConfig flexConfig; private final TraverseVisitor traverseVisitor; private final WorldEnvelopeService worldEnvelopeService; @@ -59,7 +60,7 @@ private DefaultServerRequestContext( MeterRegistry meterRegistry, RaptorConfig raptorConfig, TileRendererManager tileRendererManager, - VectorTilesResource.LayersParameters vectorTileLayers, + VectorTileConfig vectorTileConfig, WorldEnvelopeService worldEnvelopeService, RealtimeVehicleService realtimeVehicleService, VehicleRentalService vehicleRentalService, @@ -75,7 +76,7 @@ private DefaultServerRequestContext( this.meterRegistry = meterRegistry; this.raptorConfig = raptorConfig; this.tileRendererManager = tileRendererManager; - this.vectorTileLayers = vectorTileLayers; + this.vectorTileConfig = vectorTileConfig; this.vehicleRentalService = vehicleRentalService; this.flexConfig = flexConfig; this.traverseVisitor = traverseVisitor; @@ -97,7 +98,7 @@ public static DefaultServerRequestContext create( Graph graph, TransitService transitService, MeterRegistry meterRegistry, - VectorTilesResource.LayersParameters vectorTileLayers, + VectorTileConfig vectorTileConfig, WorldEnvelopeService worldEnvelopeService, RealtimeVehicleService realtimeVehicleService, VehicleRentalService vehicleRentalService, @@ -115,7 +116,7 @@ public static DefaultServerRequestContext create( meterRegistry, raptorConfig, new TileRendererManager(graph, routeRequestDefaults.preferences()), - vectorTileLayers, + vectorTileConfig, worldEnvelopeService, realtimeVehicleService, vehicleRentalService, @@ -221,7 +222,7 @@ public FlexConfig flexConfig() { @Override public VectorTilesResource.LayersParameters vectorTileLayers() { - return vectorTileLayers; + return vectorTileConfig; } @Override diff --git a/src/test/java/org/opentripplanner/TestServerContext.java b/src/test/java/org/opentripplanner/TestServerContext.java index 1f3e6491232..dd640c1f000 100644 --- a/src/test/java/org/opentripplanner/TestServerContext.java +++ b/src/test/java/org/opentripplanner/TestServerContext.java @@ -42,7 +42,7 @@ public static OtpServerRequestContext createServerContext( graph, new DefaultTransitService(transitModel), Metrics.globalRegistry, - routerConfig.vectorTileLayers(), + routerConfig.vectorTileConfig(), createWorldEnvelopeService(), createRealtimeVehicleService(transitService), createVehicleRentalService(), diff --git a/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java b/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java index 3058f622281..a59b3e3f4bc 100644 --- a/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java +++ b/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java @@ -124,7 +124,7 @@ public class TripRequestMapperTest implements PlanTestConstants { graph, transitService, Metrics.globalRegistry, - RouterConfig.DEFAULT.vectorTileLayers(), + RouterConfig.DEFAULT.vectorTileConfig(), new DefaultWorldEnvelopeService(new DefaultWorldEnvelopeRepository()), new DefaultRealtimeVehicleService(transitService), new DefaultVehicleRentalService(), diff --git a/src/test/java/org/opentripplanner/generate/doc/RouterConfigurationDocTest.java b/src/test/java/org/opentripplanner/generate/doc/RouterConfigurationDocTest.java index d13f423ffc4..a48374e755c 100644 --- a/src/test/java/org/opentripplanner/generate/doc/RouterConfigurationDocTest.java +++ b/src/test/java/org/opentripplanner/generate/doc/RouterConfigurationDocTest.java @@ -33,7 +33,7 @@ public class RouterConfigurationDocTest { .skip("flex", "sandbox/Flex.md") .skip("routingDefaults", "RouteRequest.md") .skip("updaters", "UpdaterConfig.md") - .skip("vectorTileLayers", "sandbox/MapboxVectorTilesApi.md") + .skip("vectorTiles", "sandbox/MapboxVectorTilesApi.md") .skipNestedElements("transferCacheRequests", "RouteRequest.md") .skip("rideHailingServices", "sandbox/RideHailing.md") .skip("vehicleRentalServiceDirectory", "sandbox/VehicleRentalServiceDirectory.md") diff --git a/src/test/java/org/opentripplanner/transit/speed_test/SpeedTest.java b/src/test/java/org/opentripplanner/transit/speed_test/SpeedTest.java index 642e192539c..7a11c35bace 100644 --- a/src/test/java/org/opentripplanner/transit/speed_test/SpeedTest.java +++ b/src/test/java/org/opentripplanner/transit/speed_test/SpeedTest.java @@ -29,6 +29,7 @@ import org.opentripplanner.standalone.config.BuildConfig; import org.opentripplanner.standalone.config.ConfigModel; import org.opentripplanner.standalone.config.OtpConfigLoader; +import org.opentripplanner.standalone.config.routerconfig.VectorTileConfig; import org.opentripplanner.standalone.server.DefaultServerRequestContext; import org.opentripplanner.transit.service.DefaultTransitService; import org.opentripplanner.transit.service.TransitModel; @@ -111,7 +112,7 @@ public SpeedTest( graph, new DefaultTransitService(transitModel), timer.getRegistry(), - List::of, + VectorTileConfig.DEFAULT, TestServerContext.createWorldEnvelopeService(), TestServerContext.createRealtimeVehicleService(transitService), TestServerContext.createVehicleRentalService(), diff --git a/src/test/resources/standalone/config/router-config.json b/src/test/resources/standalone/config/router-config.json index 5abb5ef87a6..f64a3b0f3b9 100644 --- a/src/test/resources/standalone/config/router-config.json +++ b/src/test/resources/standalone/config/router-config.json @@ -55,11 +55,14 @@ "accessEgress": { "maxDuration": "45m", "maxDurationForMode": { - "BIKE_RENTAL": "20m" + "BIKE_RENTAL": "20m" }, "maxStopCount": 500, "penalty": { - "FLEXIBLE" : { "timePenalty": "2m + 1.1t", "costFactor": 1.7 } + "FLEXIBLE": { + "timePenalty": "2m + 1.1t", + "costFactor": 1.7 + } } }, "itineraryFilters": { @@ -80,8 +83,12 @@ "geoidElevation": false, "maxJourneyDuration": "36h", "unpreferred": { - "agencies": ["HSL:123"], - "routes": ["HSL:456"] + "agencies": [ + "HSL:123" + ], + "routes": [ + "HSL:456" + ] }, "unpreferredCost": "10m + 2.0 x", "streetRoutingTimeout": "5s", @@ -135,8 +142,15 @@ "PREFERRED": 0 }, "transferCacheRequests": [ - { "modes": "WALK" }, - { "modes": "WALK", "wheelchairAccessibility": { "enabled": true } } + { + "modes": "WALK" + }, + { + "modes": "WALK", + "wheelchairAccessibility": { + "enabled": true + } + } ] }, "vehicleRentalServiceDirectory": { @@ -151,61 +165,63 @@ "transmodelApi": { "hideFeedId": true }, - "vectorTileLayers": [ - { - "name": "stops", - "type": "Stop", - "mapper": "Digitransit", - "maxZoom": 20, - "minZoom": 14, - "cacheMaxSeconds": 600 - }, - { - "name": "stations", - "type": "Station", - "mapper": "Digitransit", - "maxZoom": 20, - "minZoom": 12, - "cacheMaxSeconds": 600 - }, - { - "name": "rentalPlaces", - // all rental places: stations and free-floating vehicles - "type": "VehicleRental", - "mapper": "Digitransit", - "maxZoom": 20, - "minZoom": 14, - "cacheMaxSeconds": 60, - "expansionFactor": 0.25 - }, - { - "name": "rentalVehicle", - // just free-floating vehicles - "type": "VehicleRentalVehicle", - "mapper": "Digitransit", - "maxZoom": 20, - "minZoom": 14, - "cacheMaxSeconds": 60 - }, - { - "name": "rentalStation", - // just rental stations - "type": "VehicleRentalStation", - "mapper": "Digitransit", - "maxZoom": 20, - "minZoom": 14, - "cacheMaxSeconds": 600 - }, - { - "name": "vehicleParking", - "type": "VehicleParking", - "mapper": "Digitransit", - "maxZoom": 20, - "minZoom": 14, - "cacheMaxSeconds": 60, - "expansionFactor": 0.25 - } - ], + "vectorTiles": { + "layers": [ + { + "name": "stops", + "type": "Stop", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 600 + }, + { + "name": "stations", + "type": "Station", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 12, + "cacheMaxSeconds": 600 + }, + { + "name": "rentalPlaces", + // all rental places: stations and free-floating vehicles + "type": "VehicleRental", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 60, + "expansionFactor": 0.25 + }, + { + "name": "rentalVehicle", + // just free-floating vehicles + "type": "VehicleRentalVehicle", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 60 + }, + { + "name": "rentalStation", + // just rental stations + "type": "VehicleRentalStation", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 600 + }, + { + "name": "vehicleParking", + "type": "VehicleParking", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 60, + "expansionFactor": 0.25 + } + ] + }, "timetableUpdates": { "purgeExpiredData": false, "maxSnapshotFrequency": "2s" @@ -301,7 +317,9 @@ "Header-Name": "Header-Value" }, "fuzzyTripMatching": false, - "features": ["position"] + "features": [ + "position" + ] }, // Siri-ET over HTTP { @@ -345,8 +363,10 @@ "clientSecret": "very-secret", "wheelchairAccessibleProductId": "545de0c4-659f-49c6-be65-0d5e448dffd5", "bannedProductIds": [ - "1196d0dd-423b-4a81-a1d8-615367d3a365", "f58761e5-8dd5-4940-a472-872f1236c596" + "1196d0dd-423b-4a81-a1d8-615367d3a365", + "f58761e5-8dd5-4940-a472-872f1236c596" ] } ] } + From 2d31331fe0914fa99b0fb226159f29abea8f5d1e Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 16 Jan 2024 14:38:45 +0100 Subject: [PATCH 13/69] Add test for base path --- .../VehicleParkingGroupsLayerTest.java | 26 ++++++------ .../ext/vectortiles/VectorTilesResource.java | 9 ++-- .../apis/support/TileJson.java | 42 ++++++++++++++----- .../GraphInspectorVectorTileResource.java | 7 ++-- .../api/OtpServerRequestContext.java | 4 +- .../config/routerconfig/VectorTileConfig.java | 6 +-- .../server/DefaultServerRequestContext.java | 3 +- .../apis/support/TileJsonTest.java | 23 ++++++++++ 8 files changed, 81 insertions(+), 39 deletions(-) create mode 100644 src/test/java/org/opentripplanner/apis/support/TileJsonTest.java 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 1442b57fd60..66afc530e76 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 @@ -97,21 +97,23 @@ public void vehicleParkingGroupGeometryTest() { var config = """ { - "vectorTileLayers": [ - { - "name": "vehicleParkingGroups", - "type": "VehicleParkingGroup", - "mapper": "Digitransit", - "maxZoom": 20, - "minZoom": 14, - "cacheMaxSeconds": 600, - "expansionFactor": 0 - } - ] + "vectorTiles": { + "layers" :[ + { + "name": "vehicleParkingGroups", + "type": "VehicleParkingGroup", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 600, + "expansionFactor": 0 + } + ] + } } """; var nodeAdapter = newNodeAdapterForTest(config); - var tiles = VectorTileConfig.mapVectorTilesParameters(nodeAdapter, "vectorTileLayers"); + var tiles = VectorTileConfig.mapVectorTilesParameters(nodeAdapter, "vectorTiles"); assertEquals(1, tiles.layers().size()); var builder = new VehicleParkingGroupsLayerBuilderWithPublicGeometry( graph, diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java b/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java index af2715d6928..0f04e26c833 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java @@ -66,7 +66,7 @@ public Response tileGet( z, locale, Arrays.asList(requestedLayers.split(",")), - serverContext.vectorTileLayers().layers(), + serverContext.vectorTileConfig().layers(), VectorTilesResource::crateLayerBuilder, serverContext ); @@ -89,15 +89,14 @@ public TileJson getTileJson( .filter(Predicate.not(Objects::isNull)) .toList(); - return new TileJson( + var url = TileJson.tileUrl( uri, headers, requestedLayers, ignoreRouterId, - "vectorTiles", - envelope, - feedInfos + "vectorTiles" ); + return new TileJson(url, envelope, feedInfos); } private static LayerBuilder crateLayerBuilder( diff --git a/src/main/java/org/opentripplanner/apis/support/TileJson.java b/src/main/java/org/opentripplanner/apis/support/TileJson.java index 2259d72d828..0975f7eb7b8 100644 --- a/src/main/java/org/opentripplanner/apis/support/TileJson.java +++ b/src/main/java/org/opentripplanner/apis/support/TileJson.java @@ -5,6 +5,7 @@ import java.io.Serializable; import java.util.Collection; import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; import org.opentripplanner.framework.io.HttpUtils; import org.opentripplanner.model.FeedInfo; import org.opentripplanner.service.worldenvelope.model.WorldEnvelope; @@ -35,11 +36,7 @@ public class TileJson implements Serializable { public final double[] center; public TileJson( - UriInfo uri, - HttpHeaders headers, - String layers, - String ignoreRouterId, - String path, + String tileUrl, WorldEnvelope envelope, Collection feedInfos ) { @@ -53,12 +50,7 @@ public TileJson( tiles = new String[] { - "%s/otp/routers/%s/%s/%s/{z}/{x}/{y}.pbf".formatted( - HttpUtils.getBaseAddress(uri, headers), - ignoreRouterId, - path, - layers - ), + tileUrl }; bounds = @@ -72,4 +64,32 @@ public TileJson( var c = envelope.center(); center = new double[] { c.longitude(), c.latitude(), 9 }; } + + public static String tileUrl( + UriInfo uri, + HttpHeaders headers, + String layers, + String ignoreRouterId, + String path + ) { + return "%s/otp/routers/%s/%s/%s/{z}/{x}/{y}.pbf".formatted( + HttpUtils.getBaseAddress(uri, headers), + ignoreRouterId, + path, + layers + ); + } + public static String tileUrl( + UriInfo uri, + HttpHeaders headers, + String overridePath, + String layers + ) { + var strippedPath = StringUtils.stripStart(overridePath, "/"); + return "%s/%s/%s/{z}/{x}/{y}.pbf".formatted( + HttpUtils.getBaseAddress(uri, headers), + strippedPath, + layers + ); + } } diff --git a/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java b/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java index 67f92f01ee3..17cd44c1328 100644 --- a/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java +++ b/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java @@ -103,15 +103,14 @@ public TileJson getTileJson( var envelope = serverContext.worldEnvelopeService().envelope().orElseThrow(); List feedInfos = feedInfos(); - return new TileJson( + var url = TileJson.tileUrl( uri, headers, requestedLayers, ignoreRouterId, - "inspector/vectortile", - envelope, - feedInfos + "inspector/vectortile" ); + return new TileJson(url, envelope, feedInfos); } @GET diff --git a/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java b/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java index fa6ead99c5e..fa3a7069e2d 100644 --- a/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java +++ b/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java @@ -9,7 +9,6 @@ import org.opentripplanner.ext.emissions.EmissionsService; import org.opentripplanner.ext.ridehailing.RideHailingService; import org.opentripplanner.ext.stopconsolidation.StopConsolidationService; -import org.opentripplanner.ext.vectortiles.VectorTilesResource; import org.opentripplanner.framework.application.OTPFeature; import org.opentripplanner.inspector.raster.TileRendererManager; import org.opentripplanner.raptor.api.request.RaptorTuningParameters; @@ -23,6 +22,7 @@ import org.opentripplanner.service.realtimevehicles.RealtimeVehicleService; import org.opentripplanner.service.vehiclerental.VehicleRentalService; import org.opentripplanner.service.worldenvelope.WorldEnvelopeService; +import org.opentripplanner.standalone.config.routerconfig.VectorTileConfig; import org.opentripplanner.standalone.config.sandbox.FlexConfig; import org.opentripplanner.street.model.edge.Edge; import org.opentripplanner.street.search.state.State; @@ -119,7 +119,7 @@ default GraphFinder graphFinder() { FlexConfig flexConfig(); - VectorTilesResource.LayersParameters vectorTileLayers(); + VectorTileConfig vectorTileConfig(); default DataOverlayContext dataOverlayContext(RouteRequest request) { return OTPFeature.DataOverlay.isOnElseNull(() -> diff --git a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java index b3b48e19c23..288ca5dbb49 100644 --- a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java @@ -10,6 +10,7 @@ import java.util.Collection; import java.util.List; +import java.util.Optional; import javax.annotation.Nullable; import org.opentripplanner.ext.vectortiles.VectorTilesResource; import org.opentripplanner.inspector.vector.LayerParameters; @@ -38,9 +39,8 @@ public List> layers() { return layers; } - @Nullable - public String basePath() { - return basePath; + public Optional basePath() { + return Optional.ofNullable(basePath); } public static VectorTileConfig mapVectorTilesParameters(NodeAdapter node, String paramName) { diff --git a/src/main/java/org/opentripplanner/standalone/server/DefaultServerRequestContext.java b/src/main/java/org/opentripplanner/standalone/server/DefaultServerRequestContext.java index c0ac70309e6..9a586219ba1 100644 --- a/src/main/java/org/opentripplanner/standalone/server/DefaultServerRequestContext.java +++ b/src/main/java/org/opentripplanner/standalone/server/DefaultServerRequestContext.java @@ -8,7 +8,6 @@ import org.opentripplanner.ext.emissions.EmissionsService; import org.opentripplanner.ext.ridehailing.RideHailingService; import org.opentripplanner.ext.stopconsolidation.StopConsolidationService; -import org.opentripplanner.ext.vectortiles.VectorTilesResource; import org.opentripplanner.inspector.raster.TileRendererManager; import org.opentripplanner.raptor.api.request.RaptorTuningParameters; import org.opentripplanner.raptor.configure.RaptorConfig; @@ -221,7 +220,7 @@ public FlexConfig flexConfig() { } @Override - public VectorTilesResource.LayersParameters vectorTileLayers() { + public VectorTileConfig vectorTileConfig() { return vectorTileConfig; } diff --git a/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java b/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java new file mode 100644 index 00000000000..00c9a94aa24 --- /dev/null +++ b/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java @@ -0,0 +1,23 @@ +package org.opentripplanner.apis.support; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.net.URI; +import java.net.URISyntaxException; +import org.glassfish.jersey.internal.MapPropertiesDelegate; +import org.glassfish.jersey.server.ContainerRequest; +import org.glassfish.jersey.server.internal.routing.UriRoutingContext; +import org.junit.jupiter.api.Test; + +class TileJsonTest { + + @Test + void url() throws URISyntaxException { + + var uri= new URI("https://localhost:8080"); + var header = new ContainerRequest(uri, uri, "GET", null, new MapPropertiesDelegate(), null); + var uriInfo =new UriRoutingContext(header); + assertEquals("", TileJson.tileUrl(uriInfo, header, "/OTP_CT/some/config/path/", "foo,bar")); + } + +} \ No newline at end of file From 18e1ce6abe54016b2ce8acc392ce109a7dadf1f6 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 16 Jan 2024 18:23:03 +0100 Subject: [PATCH 14/69] Fix tests --- .../VehicleParkingGroupsLayerTest.java | 2 +- .../VehicleParkingsLayerTest.java | 28 ++++++++++--------- 2 files changed, 16 insertions(+), 14 deletions(-) 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 66afc530e76..1ec7d042894 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 @@ -98,7 +98,7 @@ public void vehicleParkingGroupGeometryTest() { """ { "vectorTiles": { - "layers" :[ + "layers" :[ { "name": "vehicleParkingGroups", "type": "VehicleParkingGroup", diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/VehicleParkingsLayerTest.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/VehicleParkingsLayerTest.java index b4988ab398d..fdb723b3dc7 100644 --- a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/VehicleParkingsLayerTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/VehicleParkingsLayerTest.java @@ -93,23 +93,25 @@ public void vehicleParkingGeometryTest() { var config = """ { - "vectorTileLayers": [ - { - "name": "vehicleParking", - "type": "VehicleParking", - "mapper": "Stadtnavi", - "maxZoom": 20, - "minZoom": 14, - "cacheMaxSeconds": 60, - "expansionFactor": 0 - } - ] + "vectorTiles": { + "layers" : [ + { + "name": "vehicleParking", + "type": "VehicleParking", + "mapper": "Stadtnavi", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 60, + "expansionFactor": 0 + } + ] + } } """; var nodeAdapter = newNodeAdapterForTest(config); - var tiles = VectorTileConfig.mapVectorTilesParameters(nodeAdapter, "vectorTileLayers"); + var tiles = VectorTileConfig.mapVectorTilesParameters(nodeAdapter, "vectorTiles"); assertEquals(1, tiles.layers().size()); - var builder = new VehicleParkingsLayerBuilder(graph, tiles.layers().get(0), Locale.US); + var builder = new VehicleParkingsLayerBuilder(graph, tiles.layers().getFirst(), Locale.US); List geometries = builder.getGeometries(new Envelope(0.99, 1.01, 1.99, 2.01)); From 5dac9ddf8c3359e3686c37771ed6309a8280b101 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 16 Jan 2024 22:51:53 +0100 Subject: [PATCH 15/69] Add parameter documentation for vector tiles --- doc-templates/sandbox/MapboxVectorTilesApi.md | 198 ++++++++++++ docs/sandbox/MapboxVectorTilesApi.md | 297 ++++++++++++++++++ .../vectortiles/VectorTilesConfigDocTest.java | 80 +++++ 3 files changed, 575 insertions(+) create mode 100644 doc-templates/sandbox/MapboxVectorTilesApi.md create mode 100644 src/ext-test/java/org/opentripplanner/ext/vectortiles/VectorTilesConfigDocTest.java diff --git a/doc-templates/sandbox/MapboxVectorTilesApi.md b/doc-templates/sandbox/MapboxVectorTilesApi.md new file mode 100644 index 00000000000..dfba427919a --- /dev/null +++ b/doc-templates/sandbox/MapboxVectorTilesApi.md @@ -0,0 +1,198 @@ +# Mapbox Vector Tiles API + +## Contact Info + +- HSL, Finland +- Kyyti Group Oy, Finland +- Hannes Junnila + +## Documentation + +This API produces [Mapbox vector tiles](https://docs.mapbox.com/vector-tiles/reference/), which are +used by eg. [Digitransit-ui](https://github.com/HSLdevcom/digitransit-ui) to show information about +public transit entities on the map. + +The tiles can be fetched from `/otp/routers/{routerId}/vectorTiles/{layers}/{z}/{x}/{y}.pbf`, +where `layers` is a comma separated list of layer names from the configuration. + +Translatable fields in the tiles are translated based on the `accept-language` header in requests. +Currently, only the language with the highest priority from the header is used. + +### Configuration + +To enable this you need to add the feature `otp-config.json`. + +```json +// otp-config.json +{ + "otpFeatures": { + "SandboxAPIMapboxVectorTilesApi": true + } +} +``` + +The feature must be configured in `router-config.json` as follows + +```JSON +{ + "vectorTiles": + "layers": [ + { + "name": "stops", + "type": "Stop", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 600 + }, + { + "name": "stations", + "type": "Station", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 12, + "cacheMaxSeconds": 600 + }, + // all rental places: stations and free-floating vehicles + { + "name": "citybikes", + "type": "VehicleRental", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 60, + "expansionFactor": 0.25 + }, + // just free-floating vehicles + { + "name": "rentalVehicles", + "type": "VehicleRentalVehicle", + "mapper": "DigitransitRealtime", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 60 + }, + // just rental stations + { + "name": "rentalStations", + "type": "VehicleRentalStation", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 600 + }, + // Contains just stations and real-time information for them + { + "name": "realtimeRentalStations", + "type": "VehicleRentalStation", + "mapper": "DigitransitRealtime", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 60 + }, + // This exists for backwards compatibility. At some point, we might want + // to add a new real-time parking mapper with better translation support + // and less unnecessary fields. + { + "name": "stadtnaviVehicleParking", + "type": "VehicleParking", + "mapper": "Stadtnavi", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 60, + "expansionFactor": 0.25 + }, + // no real-time, translatable fields are translated based on accept-language header + // and contains less fields than the Stadtnavi mapper + { + "name": "vehicleParking", + "type": "VehicleParking", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 600, + "expansionFactor": 0.25 + }, + { + "name": "vehicleParkingGroups", + "type": "VehicleParkingGroup", + "mapper": "Digitransit", + "maxZoom": 17, + "minZoom": 14, + "cacheMaxSeconds": 600, + "expansionFactor": 0.25 + } + ] + } +} +``` + +For each layer, the configuration includes: + +- `name` which is used in the url to fetch tiles, and as the layer name in the vector tiles. +- `type` which tells the type of the layer. Currently supported: + - `Stop` + - `Station` + - `VehicleRental`: all rental places: stations and free-floating vehicles + - `VehicleRentalVehicle`: free-floating rental vehicles + - `VehicleRentalStation`: rental stations + - `VehicleParking` + - `VehicleParkingGroup` +- `mapper` which describes the mapper converting the properties from the OTP model entities to the + vector tile properties. Currently `Digitransit` is supported for all layer types. +- `minZoom` and `maxZoom` which describe the zoom levels the layer is active for. +- `cacheMaxSeconds` which sets the cache header in the response. The lowest value of the layers + included is selected. +- `expansionFactor` How far outside its boundaries should the tile contain information. The value is + a fraction of the tile size. If you are having problem with icons and shapes being clipped at tile + edges, then increase this number. + +### Extending + +If more generic layers are created for this API, it should be moved out from the sandbox, into the +core code, with potentially leaving specific property mappers in place. + +#### Creating a new layer + +In order to create a new type of layer, you need to create a new class extending `LayerBuilder`. +You need to implement two methods, `List getGeometries(Envelope query)`, which returns a +list of geometries, with an object of type `T` as their userData in the geometry, +and `double getExpansionFactor()`, which describes how much information outside the tile bounds +should be included. This layer then needs to be added into `VectorTilesResource.layers`, with a +new `LayerType` enum as the key, and the class constructor as the value. + +A new mapper needs to be added every time a new layer is added. See below for information. + + + + +#### Creating a new mapper + +The mapping contains information of what data to include in the vector tiles. The mappers are +defined per layer. + +In order to create a new mapper for a layer, you need to create a new class +extending `PropertyMapper`. In that class, you need to implement the +method `Collection> map(T input)`. The type T is dependent on the layer for which +you implement the mapper for. It needs to return a list of attributes, as key-value pairs which will +be written into the vector tile. + +The mapper needs to be added to the `mappers` map in the layer, with a new `MapperType` enum as the +key, and a function to create the mapper, with a `Graph` object as a parameter, as the value. + +## Changelog + +- 2020-07-09: Initial version of Mapbox vector tiles API +- 2021-05-12: Make expansion factor configurable +- 2021-09-07: Rename `BikeRental` to `VehicleRental` +- 2021-10-13: Correctly serialize the vehicle rental name [#3648](https://github.com/opentripplanner/OpenTripPlanner/pull/3648) +- 2022-01-03: Add support for VehicleParking entities +- 2022-04-27: Read the headsign for frequency-only patterns correctly [#4122](https://github.com/opentripplanner/OpenTripPlanner/pull/4122) +- 2022-08-23: Remove patterns and add route gtfsTypes to stop layer [#4404](https://github.com/opentripplanner/OpenTripPlanner/pull/4404) +- 2022-10-11: Added layer for VehicleParkingGroups [#4510](https://github.com/opentripplanner/OpenTripPlanner/pull/4510) +- 2022-10-14: Add separate layers for vehicle rental place types [#4516](https://github.com/opentripplanner/OpenTripPlanner/pull/4516) +- 2022-10-19 [#4529](https://github.com/opentripplanner/OpenTripPlanner/pull/4529): + * Translatable fields are now translated based on accept-language header + * Added DigitransitRealtime for vehicle rental stations + * Changed old vehicle parking mapper to be Stadtnavi + * Added a new Digitransit vehicle parking mapper with no real-time information and less fields diff --git a/docs/sandbox/MapboxVectorTilesApi.md b/docs/sandbox/MapboxVectorTilesApi.md index 0904bd1fef6..e11fe320ef8 100644 --- a/docs/sandbox/MapboxVectorTilesApi.md +++ b/docs/sandbox/MapboxVectorTilesApi.md @@ -163,6 +163,303 @@ new `LayerType` enum as the key, and the class constructor as the value. A new mapper needs to be added every time a new layer is added. See below for information. + + + + +| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | +|------------------------------------------------------------------|:----------:|--------------------------------------------------------------------------------------------|:----------:|---------------|:-----:| +| basePath | `string` | TODO: Add short summary. | *Optional* | | 2.5 | +| [layers](#vectorTiles_layers) | `object[]` | Configuration of the individual layers for the Mapbox vector tiles. | *Optional* | | 2.0 | +|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | +|       type = "stop" | `enum` | Type of the layer. | *Required* | | 2.0 | +|       [cacheMaxSeconds](#vectorTiles_layers_0_cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | +|       [expansionFactor](#vectorTiles_layers_0_expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | +|       [mapper](#vectorTiles_layers_0_mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | +|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | +|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | +|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | +|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | +|       type = "station" | `enum` | Type of the layer. | *Required* | | 2.0 | +|       [cacheMaxSeconds](#vectorTiles_layers_1_cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | +|       [expansionFactor](#vectorTiles_layers_1_expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | +|       [mapper](#vectorTiles_layers_1_mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | +|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | +|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | +|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | +|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | +|       type = "vehiclerental" | `enum` | Type of the layer. | *Required* | | 2.0 | +|       [cacheMaxSeconds](#vectorTiles_layers__2__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | +|       [expansionFactor](#vectorTiles_layers__2__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | +|       [mapper](#vectorTiles_layers__2__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | +|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | +|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | +|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | +|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | +|       type = "vehiclerentalvehicle" | `enum` | Type of the layer. | *Required* | | 2.0 | +|       [cacheMaxSeconds](#vectorTiles_layers__3__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | +|       [expansionFactor](#vectorTiles_layers__3__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | +|       [mapper](#vectorTiles_layers__3__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | +|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | +|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | +|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | +|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | +|       type = "vehiclerentalstation" | `enum` | Type of the layer. | *Required* | | 2.0 | +|       [cacheMaxSeconds](#vectorTiles_layers__4__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | +|       [expansionFactor](#vectorTiles_layers__4__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | +|       [mapper](#vectorTiles_layers__4__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | +|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | +|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | +|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | +|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | +|       type = "vehicleparking" | `enum` | Type of the layer. | *Required* | | 2.0 | +|       [cacheMaxSeconds](#vectorTiles_layers__5__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | +|       [expansionFactor](#vectorTiles_layers__5__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | +|       [mapper](#vectorTiles_layers__5__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | +|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | +|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | +|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | + + +#### Details + +

layers

+ +**Since version:** `2.0` ∙ **Type:** `object[]` ∙ **Cardinality:** `Optional` +**Path:** /vectorTiles + +Configuration of the individual layers for the Mapbox vector tiles. + +

cacheMaxSeconds

+ +**Since version:** `2.0` ∙ **Type:** `integer` ∙ **Cardinality:** `Optional` ∙ **Default value:** `-1` +**Path:** /vectorTiles/layers/[0] + +Sets the cache header in the response. + +The lowest value of the layers included is selected. + +

expansionFactor

+ +**Since version:** `2.0` ∙ **Type:** `double` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0.25` +**Path:** /vectorTiles/layers/[0] + +How far outside its boundaries should the tile contain information. + +The value is a fraction of the tile size. If you are having problem with icons and shapes being clipped at tile edges, then increase this number. + +

mapper

+ +**Since version:** `2.0` ∙ **Type:** `string` ∙ **Cardinality:** `Required` +**Path:** /vectorTiles/layers/[0] + +Describes the mapper converting from the OTP model entities to the vector tile properties. + +Currently `Digitransit` is supported for all layer types. + +

cacheMaxSeconds

+ +**Since version:** `2.0` ∙ **Type:** `integer` ∙ **Cardinality:** `Optional` ∙ **Default value:** `-1` +**Path:** /vectorTiles/layers/[1] + +Sets the cache header in the response. + +The lowest value of the layers included is selected. + +

expansionFactor

+ +**Since version:** `2.0` ∙ **Type:** `double` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0.25` +**Path:** /vectorTiles/layers/[1] + +How far outside its boundaries should the tile contain information. + +The value is a fraction of the tile size. If you are having problem with icons and shapes being clipped at tile edges, then increase this number. + +

mapper

+ +**Since version:** `2.0` ∙ **Type:** `string` ∙ **Cardinality:** `Required` +**Path:** /vectorTiles/layers/[1] + +Describes the mapper converting from the OTP model entities to the vector tile properties. + +Currently `Digitransit` is supported for all layer types. + +

cacheMaxSeconds

+ +**Since version:** `2.0` ∙ **Type:** `integer` ∙ **Cardinality:** `Optional` ∙ **Default value:** `-1` +**Path:** /vectorTiles/layers/[2] + +Sets the cache header in the response. + +The lowest value of the layers included is selected. + +

expansionFactor

+ +**Since version:** `2.0` ∙ **Type:** `double` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0.25` +**Path:** /vectorTiles/layers/[2] + +How far outside its boundaries should the tile contain information. + +The value is a fraction of the tile size. If you are having problem with icons and shapes being clipped at tile edges, then increase this number. + +

mapper

+ +**Since version:** `2.0` ∙ **Type:** `string` ∙ **Cardinality:** `Required` +**Path:** /vectorTiles/layers/[2] + +Describes the mapper converting from the OTP model entities to the vector tile properties. + +Currently `Digitransit` is supported for all layer types. + +

cacheMaxSeconds

+ +**Since version:** `2.0` ∙ **Type:** `integer` ∙ **Cardinality:** `Optional` ∙ **Default value:** `-1` +**Path:** /vectorTiles/layers/[3] + +Sets the cache header in the response. + +The lowest value of the layers included is selected. + +

expansionFactor

+ +**Since version:** `2.0` ∙ **Type:** `double` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0.25` +**Path:** /vectorTiles/layers/[3] + +How far outside its boundaries should the tile contain information. + +The value is a fraction of the tile size. If you are having problem with icons and shapes being clipped at tile edges, then increase this number. + +

mapper

+ +**Since version:** `2.0` ∙ **Type:** `string` ∙ **Cardinality:** `Required` +**Path:** /vectorTiles/layers/[3] + +Describes the mapper converting from the OTP model entities to the vector tile properties. + +Currently `Digitransit` is supported for all layer types. + +

cacheMaxSeconds

+ +**Since version:** `2.0` ∙ **Type:** `integer` ∙ **Cardinality:** `Optional` ∙ **Default value:** `-1` +**Path:** /vectorTiles/layers/[4] + +Sets the cache header in the response. + +The lowest value of the layers included is selected. + +

expansionFactor

+ +**Since version:** `2.0` ∙ **Type:** `double` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0.25` +**Path:** /vectorTiles/layers/[4] + +How far outside its boundaries should the tile contain information. + +The value is a fraction of the tile size. If you are having problem with icons and shapes being clipped at tile edges, then increase this number. + +

mapper

+ +**Since version:** `2.0` ∙ **Type:** `string` ∙ **Cardinality:** `Required` +**Path:** /vectorTiles/layers/[4] + +Describes the mapper converting from the OTP model entities to the vector tile properties. + +Currently `Digitransit` is supported for all layer types. + +

cacheMaxSeconds

+ +**Since version:** `2.0` ∙ **Type:** `integer` ∙ **Cardinality:** `Optional` ∙ **Default value:** `-1` +**Path:** /vectorTiles/layers/[5] + +Sets the cache header in the response. + +The lowest value of the layers included is selected. + +

expansionFactor

+ +**Since version:** `2.0` ∙ **Type:** `double` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0.25` +**Path:** /vectorTiles/layers/[5] + +How far outside its boundaries should the tile contain information. + +The value is a fraction of the tile size. If you are having problem with icons and shapes being clipped at tile edges, then increase this number. + +

mapper

+ +**Since version:** `2.0` ∙ **Type:** `string` ∙ **Cardinality:** `Required` +**Path:** /vectorTiles/layers/[5] + +Describes the mapper converting from the OTP model entities to the vector tile properties. + +Currently `Digitransit` is supported for all layer types. + + + +##### Example configuration + +```JSON +// router-config.json +{ + "updaters" : [ + { + "layers" : [ + { + "name" : "stops", + "type" : "Stop", + "mapper" : "Digitransit", + "maxZoom" : 20, + "minZoom" : 14, + "cacheMaxSeconds" : 600 + }, + { + "name" : "stations", + "type" : "Station", + "mapper" : "Digitransit", + "maxZoom" : 20, + "minZoom" : 12, + "cacheMaxSeconds" : 600 + }, + { + "name" : "rentalPlaces", + "type" : "VehicleRental", + "mapper" : "Digitransit", + "maxZoom" : 20, + "minZoom" : 14, + "cacheMaxSeconds" : 60, + "expansionFactor" : 0.25 + }, + { + "name" : "rentalVehicle", + "type" : "VehicleRentalVehicle", + "mapper" : "Digitransit", + "maxZoom" : 20, + "minZoom" : 14, + "cacheMaxSeconds" : 60 + }, + { + "name" : "rentalStation", + "type" : "VehicleRentalStation", + "mapper" : "Digitransit", + "maxZoom" : 20, + "minZoom" : 14, + "cacheMaxSeconds" : 600 + }, + { + "name" : "vehicleParking", + "type" : "VehicleParking", + "mapper" : "Digitransit", + "maxZoom" : 20, + "minZoom" : 14, + "cacheMaxSeconds" : 60, + "expansionFactor" : 0.25 + } + ] + } + ] +} +``` + + + #### Creating a new mapper The mapping contains information of what data to include in the vector tiles. The mappers are diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/VectorTilesConfigDocTest.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/VectorTilesConfigDocTest.java new file mode 100644 index 00000000000..50dbd24008f --- /dev/null +++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/VectorTilesConfigDocTest.java @@ -0,0 +1,80 @@ +package org.opentripplanner.ext.vectortiles; + +import static org.opentripplanner.framework.application.OtpFileNames.ROUTER_CONFIG_FILENAME; +import static org.opentripplanner.framework.io.FileUtils.assertFileEquals; +import static org.opentripplanner.framework.io.FileUtils.readFile; +import static org.opentripplanner.framework.io.FileUtils.writeFile; +import static org.opentripplanner.framework.text.MarkdownFormatter.HEADER_4; +import static org.opentripplanner.generate.doc.framework.DocsTestConstants.DOCS_ROOT; +import static org.opentripplanner.generate.doc.framework.DocsTestConstants.TEMPLATE_ROOT; +import static org.opentripplanner.generate.doc.framework.TemplateUtil.replaceSection; +import static org.opentripplanner.standalone.config.framework.json.JsonSupport.jsonNodeFromResource; + +import java.io.File; +import org.junit.jupiter.api.Test; +import org.opentripplanner.generate.doc.framework.DocBuilder; +import org.opentripplanner.generate.doc.framework.GeneratesDocumentation; +import org.opentripplanner.generate.doc.framework.ParameterDetailsList; +import org.opentripplanner.generate.doc.framework.ParameterSummaryTable; +import org.opentripplanner.generate.doc.framework.SkipNodes; +import org.opentripplanner.standalone.config.RouterConfig; +import org.opentripplanner.standalone.config.framework.json.NodeAdapter; + +@GeneratesDocumentation +public class VectorTilesConfigDocTest { + + private static final String DOCUMENT = "sandbox/MapboxVectorTilesApi.md"; + private static final File TEMPLATE = new File(TEMPLATE_ROOT, DOCUMENT); + private static final File OUT_FILE = new File(DOCS_ROOT, DOCUMENT); + private static final SkipNodes SKIP_NODES = SkipNodes.of().build(); + private static final String ROUTER_CONFIG_PATH = "standalone/config/" + ROUTER_CONFIG_FILENAME; + + @Test + public void updateDoc() { + NodeAdapter node = readVectorTiles(); + + // Read and close inout file (same as output file) + String template = readFile(TEMPLATE); + String original = readFile(OUT_FILE); + + template = replaceSection(template, "parameters", updaterDoc(node)); + + writeFile(OUT_FILE, template); + assertFileEquals(original, OUT_FILE); + } + + private NodeAdapter readVectorTiles() { + var json = jsonNodeFromResource(ROUTER_CONFIG_PATH); + var conf = new RouterConfig(json, ROUTER_CONFIG_PATH, false); + return conf.asNodeAdapter().child("vectorTiles"); + } + + private String updaterDoc(NodeAdapter node) { + DocBuilder buf = new DocBuilder(); + addParameterSummaryTable(buf, node); + addDetailsSection(buf, node); + addExample(buf, node); + return buf.toString(); + } + + private void addParameterSummaryTable(DocBuilder buf, NodeAdapter node) { + buf.addSection(new ParameterSummaryTable(SKIP_NODES).createTable(node).toMarkdownTable()); + } + + private void addDetailsSection(DocBuilder buf, NodeAdapter node) { + String details = getParameterDetailsTable(node); + + if (!details.isBlank()) { + buf.header(4, "Details", null).addSection(details); + } + } + + private String getParameterDetailsTable(NodeAdapter node) { + return ParameterDetailsList.listParametersWithDetails(node, SKIP_NODES, HEADER_4); + } + + private void addExample(DocBuilder buf, NodeAdapter node) { + buf.addSection("##### Example configuration"); + buf.addUpdaterExample(ROUTER_CONFIG_FILENAME, node.rawNode()); + } +} From 6bd6e08d6574df857506922e8b4c150b6e596065 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 17 Jan 2024 11:56:58 +0100 Subject: [PATCH 16/69] Generate docs for vector tiles --- docs/sandbox/MapboxVectorTilesApi.md | 104 +++++++++--------- .../ext/vectortiles/VectorTilesResource.java | 8 +- .../apis/support/TileJson.java | 30 ++--- .../GraphInspectorVectorTileResource.java | 2 +- .../config/routerconfig/VectorTileConfig.java | 21 ++-- .../apis/support/TileJsonTest.java | 10 +- 6 files changed, 80 insertions(+), 95 deletions(-) diff --git a/docs/sandbox/MapboxVectorTilesApi.md b/docs/sandbox/MapboxVectorTilesApi.md index e11fe320ef8..5f86af742f0 100644 --- a/docs/sandbox/MapboxVectorTilesApi.md +++ b/docs/sandbox/MapboxVectorTilesApi.md @@ -167,58 +167,58 @@ A new mapper needs to be added every time a new layer is added. See below for in -| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | -|------------------------------------------------------------------|:----------:|--------------------------------------------------------------------------------------------|:----------:|---------------|:-----:| -| basePath | `string` | TODO: Add short summary. | *Optional* | | 2.5 | -| [layers](#vectorTiles_layers) | `object[]` | Configuration of the individual layers for the Mapbox vector tiles. | *Optional* | | 2.0 | -|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | -|       type = "stop" | `enum` | Type of the layer. | *Required* | | 2.0 | -|       [cacheMaxSeconds](#vectorTiles_layers_0_cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | -|       [expansionFactor](#vectorTiles_layers_0_expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | -|       [mapper](#vectorTiles_layers_0_mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | -|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | -|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | -|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | -|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | -|       type = "station" | `enum` | Type of the layer. | *Required* | | 2.0 | -|       [cacheMaxSeconds](#vectorTiles_layers_1_cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | -|       [expansionFactor](#vectorTiles_layers_1_expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | -|       [mapper](#vectorTiles_layers_1_mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | -|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | -|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | -|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | -|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | -|       type = "vehiclerental" | `enum` | Type of the layer. | *Required* | | 2.0 | -|       [cacheMaxSeconds](#vectorTiles_layers__2__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | -|       [expansionFactor](#vectorTiles_layers__2__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | -|       [mapper](#vectorTiles_layers__2__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | -|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | -|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | -|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | -|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | -|       type = "vehiclerentalvehicle" | `enum` | Type of the layer. | *Required* | | 2.0 | -|       [cacheMaxSeconds](#vectorTiles_layers__3__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | -|       [expansionFactor](#vectorTiles_layers__3__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | -|       [mapper](#vectorTiles_layers__3__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | -|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | -|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | -|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | -|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | -|       type = "vehiclerentalstation" | `enum` | Type of the layer. | *Required* | | 2.0 | -|       [cacheMaxSeconds](#vectorTiles_layers__4__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | -|       [expansionFactor](#vectorTiles_layers__4__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | -|       [mapper](#vectorTiles_layers__4__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | -|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | -|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | -|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | -|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | -|       type = "vehicleparking" | `enum` | Type of the layer. | *Required* | | 2.0 | -|       [cacheMaxSeconds](#vectorTiles_layers__5__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | -|       [expansionFactor](#vectorTiles_layers__5__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | -|       [mapper](#vectorTiles_layers__5__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | -|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | -|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | -|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | +| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | +|------------------------------------------------------------------|:----------:|--------------------------------------------------------------------------------------------|:----------:|--------------------------------------|:-----:| +| basePath | `string` | TODO: Add short summary. | *Optional* | `"/otp/routers/default/vectorTiles"` | 2.5 | +| [layers](#vectorTiles_layers) | `object[]` | Configuration of the individual layers for the Mapbox vector tiles. | *Optional* | | 2.0 | +|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | +|       type = "stop" | `enum` | Type of the layer. | *Required* | | 2.0 | +|       [cacheMaxSeconds](#vectorTiles_layers_0_cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | +|       [expansionFactor](#vectorTiles_layers_0_expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | +|       [mapper](#vectorTiles_layers_0_mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | +|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | +|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | +|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | +|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | +|       type = "station" | `enum` | Type of the layer. | *Required* | | 2.0 | +|       [cacheMaxSeconds](#vectorTiles_layers_1_cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | +|       [expansionFactor](#vectorTiles_layers_1_expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | +|       [mapper](#vectorTiles_layers_1_mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | +|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | +|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | +|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | +|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | +|       type = "vehiclerental" | `enum` | Type of the layer. | *Required* | | 2.0 | +|       [cacheMaxSeconds](#vectorTiles_layers__2__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | +|       [expansionFactor](#vectorTiles_layers__2__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | +|       [mapper](#vectorTiles_layers__2__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | +|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | +|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | +|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | +|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | +|       type = "vehiclerentalvehicle" | `enum` | Type of the layer. | *Required* | | 2.0 | +|       [cacheMaxSeconds](#vectorTiles_layers__3__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | +|       [expansionFactor](#vectorTiles_layers__3__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | +|       [mapper](#vectorTiles_layers__3__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | +|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | +|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | +|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | +|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | +|       type = "vehiclerentalstation" | `enum` | Type of the layer. | *Required* | | 2.0 | +|       [cacheMaxSeconds](#vectorTiles_layers__4__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | +|       [expansionFactor](#vectorTiles_layers__4__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | +|       [mapper](#vectorTiles_layers__4__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | +|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | +|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | +|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | +|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | +|       type = "vehicleparking" | `enum` | Type of the layer. | *Required* | | 2.0 | +|       [cacheMaxSeconds](#vectorTiles_layers__5__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | +|       [expansionFactor](#vectorTiles_layers__5__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | +|       [mapper](#vectorTiles_layers__5__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | +|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | +|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | +|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | #### Details diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java b/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java index 0f04e26c833..d2796bf63d3 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java @@ -89,13 +89,7 @@ public TileJson getTileJson( .filter(Predicate.not(Objects::isNull)) .toList(); - var url = TileJson.tileUrl( - uri, - headers, - requestedLayers, - ignoreRouterId, - "vectorTiles" - ); + var url = TileJson.tileUrl(uri, headers, requestedLayers, ignoreRouterId, "vectorTiles"); return new TileJson(url, envelope, feedInfos); } diff --git a/src/main/java/org/opentripplanner/apis/support/TileJson.java b/src/main/java/org/opentripplanner/apis/support/TileJson.java index 0975f7eb7b8..b8f8fc8d27c 100644 --- a/src/main/java/org/opentripplanner/apis/support/TileJson.java +++ b/src/main/java/org/opentripplanner/apis/support/TileJson.java @@ -35,11 +35,7 @@ public class TileJson implements Serializable { public final double[] bounds; public final double[] center; - public TileJson( - String tileUrl, - WorldEnvelope envelope, - Collection feedInfos - ) { + public TileJson(String tileUrl, WorldEnvelope envelope, Collection feedInfos) { attribution = feedInfos .stream() @@ -48,10 +44,7 @@ public TileJson( ) .collect(Collectors.joining(", ")); - tiles = - new String[] { - tileUrl - }; + tiles = new String[] { tileUrl }; bounds = new double[] { @@ -73,12 +66,13 @@ public static String tileUrl( String path ) { return "%s/otp/routers/%s/%s/%s/{z}/{x}/{y}.pbf".formatted( - HttpUtils.getBaseAddress(uri, headers), - ignoreRouterId, - path, - layers - ); + HttpUtils.getBaseAddress(uri, headers), + ignoreRouterId, + path, + layers + ); } + public static String tileUrl( UriInfo uri, HttpHeaders headers, @@ -87,9 +81,9 @@ public static String tileUrl( ) { var strippedPath = StringUtils.stripStart(overridePath, "/"); return "%s/%s/%s/{z}/{x}/{y}.pbf".formatted( - HttpUtils.getBaseAddress(uri, headers), - strippedPath, - layers - ); + HttpUtils.getBaseAddress(uri, headers), + strippedPath, + layers + ); } } diff --git a/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java b/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java index 17cd44c1328..4015d3073ac 100644 --- a/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java +++ b/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java @@ -108,7 +108,7 @@ public TileJson getTileJson( headers, requestedLayers, ignoreRouterId, - "inspector/vectortile" + "inspector/vectortile" ); return new TileJson(url, envelope, feedInfos); } diff --git a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java index 288ca5dbb49..e4905d0f63b 100644 --- a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java @@ -5,33 +5,32 @@ import static org.opentripplanner.inspector.vector.LayerParameters.MAX_ZOOM; import static org.opentripplanner.inspector.vector.LayerParameters.MIN_ZOOM; import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_0; -import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_1; import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_5; import java.util.Collection; import java.util.List; -import java.util.Optional; -import javax.annotation.Nullable; +import java.util.Objects; import org.opentripplanner.ext.vectortiles.VectorTilesResource; import org.opentripplanner.inspector.vector.LayerParameters; import org.opentripplanner.standalone.config.framework.json.NodeAdapter; -import org.opentripplanner.standalone.config.framework.json.ParameterBuilder; public class VectorTileConfig implements VectorTilesResource.LayersParameters { - public static final VectorTileConfig DEFAULT = new VectorTileConfig(List.of(), null); + public static final VectorTileConfig DEFAULT = new VectorTileConfig( + List.of(), + "/otp/routers/default/vectorTiles" + ); private final List> layers; - @Nullable private final String basePath; VectorTileConfig( Collection> layers, - @Nullable String basePath + String basePath ) { this.layers = List.copyOf(layers); - this.basePath = basePath; + this.basePath = Objects.requireNonNull(basePath); } @Override @@ -39,8 +38,8 @@ public List> layers() { return layers; } - public Optional basePath() { - return Optional.ofNullable(basePath); + public String basePath() { + return basePath; } public static VectorTileConfig mapVectorTilesParameters(NodeAdapter node, String paramName) { @@ -51,7 +50,7 @@ public static VectorTileConfig mapVectorTilesParameters(NodeAdapter node, String .since(V2_0) .summary("Configuration of the individual layers for the Mapbox vector tiles.") .asObjects(VectorTileConfig::mapLayer), - root.of("basePath").since(V2_5).asString(null) + root.of("basePath").since(V2_5).asString(DEFAULT.basePath) ); } diff --git a/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java b/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java index 00c9a94aa24..4d21ee315ea 100644 --- a/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java +++ b/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java @@ -13,11 +13,9 @@ class TileJsonTest { @Test void url() throws URISyntaxException { - - var uri= new URI("https://localhost:8080"); + var uri = new URI("https://localhost:8080"); var header = new ContainerRequest(uri, uri, "GET", null, new MapPropertiesDelegate(), null); - var uriInfo =new UriRoutingContext(header); - assertEquals("", TileJson.tileUrl(uriInfo, header, "/OTP_CT/some/config/path/", "foo,bar")); + var uriInfo = new UriRoutingContext(header); + assertEquals("", TileJson.tileUrl(uriInfo, header, "/OTP_CT/some/config/path/", "foo,bar")); } - -} \ No newline at end of file +} From 586f692922b259a19eaf621e8b2e1538803e6dab Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 17 Jan 2024 12:19:18 +0100 Subject: [PATCH 17/69] Use new config option in resource --- docs/sandbox/MapboxVectorTilesApi.md | 104 +++++++++--------- .../ext/vectortiles/VectorTilesResource.java | 11 +- .../apis/support/TileJson.java | 5 +- .../GraphInspectorVectorTileResource.java | 2 +- .../config/routerconfig/VectorTileConfig.java | 16 +-- .../apis/support/TileJsonTest.java | 20 +++- 6 files changed, 90 insertions(+), 68 deletions(-) diff --git a/docs/sandbox/MapboxVectorTilesApi.md b/docs/sandbox/MapboxVectorTilesApi.md index 5f86af742f0..e11fe320ef8 100644 --- a/docs/sandbox/MapboxVectorTilesApi.md +++ b/docs/sandbox/MapboxVectorTilesApi.md @@ -167,58 +167,58 @@ A new mapper needs to be added every time a new layer is added. See below for in -| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | -|------------------------------------------------------------------|:----------:|--------------------------------------------------------------------------------------------|:----------:|--------------------------------------|:-----:| -| basePath | `string` | TODO: Add short summary. | *Optional* | `"/otp/routers/default/vectorTiles"` | 2.5 | -| [layers](#vectorTiles_layers) | `object[]` | Configuration of the individual layers for the Mapbox vector tiles. | *Optional* | | 2.0 | -|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | -|       type = "stop" | `enum` | Type of the layer. | *Required* | | 2.0 | -|       [cacheMaxSeconds](#vectorTiles_layers_0_cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | -|       [expansionFactor](#vectorTiles_layers_0_expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | -|       [mapper](#vectorTiles_layers_0_mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | -|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | -|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | -|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | -|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | -|       type = "station" | `enum` | Type of the layer. | *Required* | | 2.0 | -|       [cacheMaxSeconds](#vectorTiles_layers_1_cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | -|       [expansionFactor](#vectorTiles_layers_1_expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | -|       [mapper](#vectorTiles_layers_1_mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | -|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | -|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | -|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | -|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | -|       type = "vehiclerental" | `enum` | Type of the layer. | *Required* | | 2.0 | -|       [cacheMaxSeconds](#vectorTiles_layers__2__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | -|       [expansionFactor](#vectorTiles_layers__2__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | -|       [mapper](#vectorTiles_layers__2__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | -|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | -|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | -|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | -|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | -|       type = "vehiclerentalvehicle" | `enum` | Type of the layer. | *Required* | | 2.0 | -|       [cacheMaxSeconds](#vectorTiles_layers__3__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | -|       [expansionFactor](#vectorTiles_layers__3__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | -|       [mapper](#vectorTiles_layers__3__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | -|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | -|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | -|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | -|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | -|       type = "vehiclerentalstation" | `enum` | Type of the layer. | *Required* | | 2.0 | -|       [cacheMaxSeconds](#vectorTiles_layers__4__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | -|       [expansionFactor](#vectorTiles_layers__4__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | -|       [mapper](#vectorTiles_layers__4__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | -|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | -|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | -|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | -|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | -|       type = "vehicleparking" | `enum` | Type of the layer. | *Required* | | 2.0 | -|       [cacheMaxSeconds](#vectorTiles_layers__5__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | -|       [expansionFactor](#vectorTiles_layers__5__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | -|       [mapper](#vectorTiles_layers__5__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | -|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | -|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | -|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | +| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | +|------------------------------------------------------------------|:----------:|--------------------------------------------------------------------------------------------|:----------:|---------------|:-----:| +| basePath | `string` | TODO: Add short summary. | *Optional* | | 2.5 | +| [layers](#vectorTiles_layers) | `object[]` | Configuration of the individual layers for the Mapbox vector tiles. | *Optional* | | 2.0 | +|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | +|       type = "stop" | `enum` | Type of the layer. | *Required* | | 2.0 | +|       [cacheMaxSeconds](#vectorTiles_layers_0_cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | +|       [expansionFactor](#vectorTiles_layers_0_expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | +|       [mapper](#vectorTiles_layers_0_mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | +|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | +|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | +|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | +|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | +|       type = "station" | `enum` | Type of the layer. | *Required* | | 2.0 | +|       [cacheMaxSeconds](#vectorTiles_layers_1_cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | +|       [expansionFactor](#vectorTiles_layers_1_expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | +|       [mapper](#vectorTiles_layers_1_mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | +|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | +|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | +|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | +|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | +|       type = "vehiclerental" | `enum` | Type of the layer. | *Required* | | 2.0 | +|       [cacheMaxSeconds](#vectorTiles_layers__2__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | +|       [expansionFactor](#vectorTiles_layers__2__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | +|       [mapper](#vectorTiles_layers__2__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | +|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | +|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | +|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | +|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | +|       type = "vehiclerentalvehicle" | `enum` | Type of the layer. | *Required* | | 2.0 | +|       [cacheMaxSeconds](#vectorTiles_layers__3__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | +|       [expansionFactor](#vectorTiles_layers__3__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | +|       [mapper](#vectorTiles_layers__3__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | +|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | +|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | +|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | +|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | +|       type = "vehiclerentalstation" | `enum` | Type of the layer. | *Required* | | 2.0 | +|       [cacheMaxSeconds](#vectorTiles_layers__4__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | +|       [expansionFactor](#vectorTiles_layers__4__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | +|       [mapper](#vectorTiles_layers__4__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | +|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | +|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | +|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | +|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | +|       type = "vehicleparking" | `enum` | Type of the layer. | *Required* | | 2.0 | +|       [cacheMaxSeconds](#vectorTiles_layers__5__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | +|       [expansionFactor](#vectorTiles_layers__5__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | +|       [mapper](#vectorTiles_layers__5__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | +|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | +|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | +|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | #### Details diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java b/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java index d2796bf63d3..e1c119713d1 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java @@ -89,7 +89,16 @@ public TileJson getTileJson( .filter(Predicate.not(Objects::isNull)) .toList(); - var url = TileJson.tileUrl(uri, headers, requestedLayers, ignoreRouterId, "vectorTiles"); + var url = serverContext + .vectorTileConfig() + .basePath() + .map(overrideBasePath -> + TileJson.overrideBasePath(uri, headers, overrideBasePath, requestedLayers) + ) + .orElseGet(() -> + TileJson.defaultBasePath(uri, headers, requestedLayers, ignoreRouterId, "vectorTiles") + ); + return new TileJson(url, envelope, feedInfos); } diff --git a/src/main/java/org/opentripplanner/apis/support/TileJson.java b/src/main/java/org/opentripplanner/apis/support/TileJson.java index b8f8fc8d27c..840542d68a8 100644 --- a/src/main/java/org/opentripplanner/apis/support/TileJson.java +++ b/src/main/java/org/opentripplanner/apis/support/TileJson.java @@ -58,7 +58,7 @@ public TileJson(String tileUrl, WorldEnvelope envelope, Collection fee center = new double[] { c.longitude(), c.latitude(), 9 }; } - public static String tileUrl( + public static String defaultBasePath( UriInfo uri, HttpHeaders headers, String layers, @@ -73,13 +73,14 @@ public static String tileUrl( ); } - public static String tileUrl( + public static String overrideBasePath( UriInfo uri, HttpHeaders headers, String overridePath, String layers ) { var strippedPath = StringUtils.stripStart(overridePath, "/"); + strippedPath = StringUtils.stripEnd(strippedPath, "/"); return "%s/%s/%s/{z}/{x}/{y}.pbf".formatted( HttpUtils.getBaseAddress(uri, headers), strippedPath, diff --git a/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java b/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java index 4015d3073ac..ada9381ec1d 100644 --- a/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java +++ b/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java @@ -103,7 +103,7 @@ public TileJson getTileJson( var envelope = serverContext.worldEnvelopeService().envelope().orElseThrow(); List feedInfos = feedInfos(); - var url = TileJson.tileUrl( + var url = TileJson.defaultBasePath( uri, headers, requestedLayers, diff --git a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java index e4905d0f63b..df353f40079 100644 --- a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java @@ -10,6 +10,8 @@ import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.Optional; +import javax.annotation.Nullable; import org.opentripplanner.ext.vectortiles.VectorTilesResource; import org.opentripplanner.inspector.vector.LayerParameters; import org.opentripplanner.standalone.config.framework.json.NodeAdapter; @@ -17,20 +19,18 @@ public class VectorTileConfig implements VectorTilesResource.LayersParameters { - public static final VectorTileConfig DEFAULT = new VectorTileConfig( - List.of(), - "/otp/routers/default/vectorTiles" - ); + public static final VectorTileConfig DEFAULT = new VectorTileConfig(List.of(), null); private final List> layers; + @Nullable private final String basePath; VectorTileConfig( Collection> layers, - String basePath + @Nullable String basePath ) { this.layers = List.copyOf(layers); - this.basePath = Objects.requireNonNull(basePath); + this.basePath = basePath; } @Override @@ -38,8 +38,8 @@ public List> layers() { return layers; } - public String basePath() { - return basePath; + public Optional basePath() { + return Optional.ofNullable(basePath); } public static VectorTileConfig mapVectorTilesParameters(NodeAdapter node, String paramName) { diff --git a/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java b/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java index 4d21ee315ea..890dc09aa92 100644 --- a/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java +++ b/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java @@ -7,15 +7,27 @@ import org.glassfish.jersey.internal.MapPropertiesDelegate; import org.glassfish.jersey.server.ContainerRequest; import org.glassfish.jersey.server.internal.routing.UriRoutingContext; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; class TileJsonTest { - @Test - void url() throws URISyntaxException { + @ParameterizedTest + @ValueSource( + strings = { + "/otp_ct/vectorTiles", + "otp_ct/vectorTiles/", + "otp_ct/vectorTiles///", + "///otp_ct/vectorTiles/", + } + ) + void overrideBasePath(String basePath) throws URISyntaxException { var uri = new URI("https://localhost:8080"); var header = new ContainerRequest(uri, uri, "GET", null, new MapPropertiesDelegate(), null); var uriInfo = new UriRoutingContext(header); - assertEquals("", TileJson.tileUrl(uriInfo, header, "/OTP_CT/some/config/path/", "foo,bar")); + assertEquals( + "https://localhost:8080/otp_ct/vectorTiles/stops,rentalVehicles/{z}/{x}/{y}.pbf", + TileJson.overrideBasePath(uriInfo, header, basePath, "stops,rentalVehicles") + ); } } From bf4605b7f509965a1aba27792cb887b394e000e7 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 17 Jan 2024 12:46:54 +0100 Subject: [PATCH 18/69] Improve documentation --- docs/sandbox/MapboxVectorTilesApi.md | 261 +----------------- .../vectortiles/VectorTilesConfigDocTest.java | 19 +- .../ext/vectortiles/router-config.json | 16 ++ .../standalone/config/router-config.json | 1 + 4 files changed, 35 insertions(+), 262 deletions(-) create mode 100644 src/ext/resources/org/opentripplanner/ext/vectortiles/router-config.json diff --git a/docs/sandbox/MapboxVectorTilesApi.md b/docs/sandbox/MapboxVectorTilesApi.md index e11fe320ef8..547eb3501c1 100644 --- a/docs/sandbox/MapboxVectorTilesApi.md +++ b/docs/sandbox/MapboxVectorTilesApi.md @@ -167,58 +167,17 @@ A new mapper needs to be added every time a new layer is added. See below for in -| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | -|------------------------------------------------------------------|:----------:|--------------------------------------------------------------------------------------------|:----------:|---------------|:-----:| -| basePath | `string` | TODO: Add short summary. | *Optional* | | 2.5 | -| [layers](#vectorTiles_layers) | `object[]` | Configuration of the individual layers for the Mapbox vector tiles. | *Optional* | | 2.0 | -|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | -|       type = "stop" | `enum` | Type of the layer. | *Required* | | 2.0 | -|       [cacheMaxSeconds](#vectorTiles_layers_0_cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | -|       [expansionFactor](#vectorTiles_layers_0_expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | -|       [mapper](#vectorTiles_layers_0_mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | -|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | -|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | -|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | -|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | -|       type = "station" | `enum` | Type of the layer. | *Required* | | 2.0 | -|       [cacheMaxSeconds](#vectorTiles_layers_1_cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | -|       [expansionFactor](#vectorTiles_layers_1_expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | -|       [mapper](#vectorTiles_layers_1_mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | -|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | -|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | -|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | -|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | -|       type = "vehiclerental" | `enum` | Type of the layer. | *Required* | | 2.0 | -|       [cacheMaxSeconds](#vectorTiles_layers__2__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | -|       [expansionFactor](#vectorTiles_layers__2__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | -|       [mapper](#vectorTiles_layers__2__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | -|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | -|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | -|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | -|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | -|       type = "vehiclerentalvehicle" | `enum` | Type of the layer. | *Required* | | 2.0 | -|       [cacheMaxSeconds](#vectorTiles_layers__3__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | -|       [expansionFactor](#vectorTiles_layers__3__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | -|       [mapper](#vectorTiles_layers__3__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | -|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | -|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | -|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | -|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | -|       type = "vehiclerentalstation" | `enum` | Type of the layer. | *Required* | | 2.0 | -|       [cacheMaxSeconds](#vectorTiles_layers__4__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | -|       [expansionFactor](#vectorTiles_layers__4__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | -|       [mapper](#vectorTiles_layers__4__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | -|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | -|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | -|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | -|    { object } | `object` | Nested object in array. The object type is determined by the parameters. | *Optional* | | 2.0 | -|       type = "vehicleparking" | `enum` | Type of the layer. | *Required* | | 2.0 | -|       [cacheMaxSeconds](#vectorTiles_layers__5__cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | -|       [expansionFactor](#vectorTiles_layers__5__expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | -|       [mapper](#vectorTiles_layers__5__mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | -|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | -|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | -|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | +| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | +|----------------------------------------------------------------|:----------:|--------------------------------------------------------------------------------------------|:----------:|---------------|:-----:| +| basePath | `string` | TODO: Add short summary. | *Optional* | | 2.5 | +| [layers](#vectorTiles_layers) | `object[]` | Configuration of the individual layers for the Mapbox vector tiles. | *Optional* | | 2.0 | +|       type = "stop" | `enum` | Type of the layer. | *Required* | | 2.0 | +|       [cacheMaxSeconds](#vectorTiles_layers_0_cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | +|       [expansionFactor](#vectorTiles_layers_0_expansionFactor) | `double` | How far outside its boundaries should the tile contain information. | *Optional* | `0.25` | 2.0 | +|       [mapper](#vectorTiles_layers_0_mapper) | `string` | Describes the mapper converting from the OTP model entities to the vector tile properties. | *Required* | | 2.0 | +|       maxZoom | `integer` | Maximum zoom levels the layer is active for. | *Optional* | `20` | 2.0 | +|       minZoom | `integer` | Minimum zoom levels the layer is active for. | *Optional* | `9` | 2.0 | +|       name | `string` | Used in the url to fetch tiles, and as the layer name in the vector tiles. | *Required* | | 2.0 | #### Details @@ -257,206 +216,8 @@ Describes the mapper converting from the OTP model entities to the vector tile p Currently `Digitransit` is supported for all layer types. -

cacheMaxSeconds

-**Since version:** `2.0` ∙ **Type:** `integer` ∙ **Cardinality:** `Optional` ∙ **Default value:** `-1` -**Path:** /vectorTiles/layers/[1] - -Sets the cache header in the response. - -The lowest value of the layers included is selected. - -

expansionFactor

- -**Since version:** `2.0` ∙ **Type:** `double` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0.25` -**Path:** /vectorTiles/layers/[1] - -How far outside its boundaries should the tile contain information. - -The value is a fraction of the tile size. If you are having problem with icons and shapes being clipped at tile edges, then increase this number. - -

mapper

- -**Since version:** `2.0` ∙ **Type:** `string` ∙ **Cardinality:** `Required` -**Path:** /vectorTiles/layers/[1] - -Describes the mapper converting from the OTP model entities to the vector tile properties. - -Currently `Digitransit` is supported for all layer types. - -

cacheMaxSeconds

- -**Since version:** `2.0` ∙ **Type:** `integer` ∙ **Cardinality:** `Optional` ∙ **Default value:** `-1` -**Path:** /vectorTiles/layers/[2] - -Sets the cache header in the response. - -The lowest value of the layers included is selected. - -

expansionFactor

- -**Since version:** `2.0` ∙ **Type:** `double` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0.25` -**Path:** /vectorTiles/layers/[2] - -How far outside its boundaries should the tile contain information. - -The value is a fraction of the tile size. If you are having problem with icons and shapes being clipped at tile edges, then increase this number. - -

mapper

- -**Since version:** `2.0` ∙ **Type:** `string` ∙ **Cardinality:** `Required` -**Path:** /vectorTiles/layers/[2] - -Describes the mapper converting from the OTP model entities to the vector tile properties. - -Currently `Digitransit` is supported for all layer types. - -

cacheMaxSeconds

- -**Since version:** `2.0` ∙ **Type:** `integer` ∙ **Cardinality:** `Optional` ∙ **Default value:** `-1` -**Path:** /vectorTiles/layers/[3] - -Sets the cache header in the response. - -The lowest value of the layers included is selected. - -

expansionFactor

- -**Since version:** `2.0` ∙ **Type:** `double` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0.25` -**Path:** /vectorTiles/layers/[3] - -How far outside its boundaries should the tile contain information. - -The value is a fraction of the tile size. If you are having problem with icons and shapes being clipped at tile edges, then increase this number. - -

mapper

-**Since version:** `2.0` ∙ **Type:** `string` ∙ **Cardinality:** `Required` -**Path:** /vectorTiles/layers/[3] - -Describes the mapper converting from the OTP model entities to the vector tile properties. - -Currently `Digitransit` is supported for all layer types. - -

cacheMaxSeconds

- -**Since version:** `2.0` ∙ **Type:** `integer` ∙ **Cardinality:** `Optional` ∙ **Default value:** `-1` -**Path:** /vectorTiles/layers/[4] - -Sets the cache header in the response. - -The lowest value of the layers included is selected. - -

expansionFactor

- -**Since version:** `2.0` ∙ **Type:** `double` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0.25` -**Path:** /vectorTiles/layers/[4] - -How far outside its boundaries should the tile contain information. - -The value is a fraction of the tile size. If you are having problem with icons and shapes being clipped at tile edges, then increase this number. - -

mapper

- -**Since version:** `2.0` ∙ **Type:** `string` ∙ **Cardinality:** `Required` -**Path:** /vectorTiles/layers/[4] - -Describes the mapper converting from the OTP model entities to the vector tile properties. - -Currently `Digitransit` is supported for all layer types. - -

cacheMaxSeconds

- -**Since version:** `2.0` ∙ **Type:** `integer` ∙ **Cardinality:** `Optional` ∙ **Default value:** `-1` -**Path:** /vectorTiles/layers/[5] - -Sets the cache header in the response. - -The lowest value of the layers included is selected. - -

expansionFactor

- -**Since version:** `2.0` ∙ **Type:** `double` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0.25` -**Path:** /vectorTiles/layers/[5] - -How far outside its boundaries should the tile contain information. - -The value is a fraction of the tile size. If you are having problem with icons and shapes being clipped at tile edges, then increase this number. - -

mapper

- -**Since version:** `2.0` ∙ **Type:** `string` ∙ **Cardinality:** `Required` -**Path:** /vectorTiles/layers/[5] - -Describes the mapper converting from the OTP model entities to the vector tile properties. - -Currently `Digitransit` is supported for all layer types. - - - -##### Example configuration - -```JSON -// router-config.json -{ - "updaters" : [ - { - "layers" : [ - { - "name" : "stops", - "type" : "Stop", - "mapper" : "Digitransit", - "maxZoom" : 20, - "minZoom" : 14, - "cacheMaxSeconds" : 600 - }, - { - "name" : "stations", - "type" : "Station", - "mapper" : "Digitransit", - "maxZoom" : 20, - "minZoom" : 12, - "cacheMaxSeconds" : 600 - }, - { - "name" : "rentalPlaces", - "type" : "VehicleRental", - "mapper" : "Digitransit", - "maxZoom" : 20, - "minZoom" : 14, - "cacheMaxSeconds" : 60, - "expansionFactor" : 0.25 - }, - { - "name" : "rentalVehicle", - "type" : "VehicleRentalVehicle", - "mapper" : "Digitransit", - "maxZoom" : 20, - "minZoom" : 14, - "cacheMaxSeconds" : 60 - }, - { - "name" : "rentalStation", - "type" : "VehicleRentalStation", - "mapper" : "Digitransit", - "maxZoom" : 20, - "minZoom" : 14, - "cacheMaxSeconds" : 600 - }, - { - "name" : "vehicleParking", - "type" : "VehicleParking", - "mapper" : "Digitransit", - "maxZoom" : 20, - "minZoom" : 14, - "cacheMaxSeconds" : 60, - "expansionFactor" : 0.25 - } - ] - } - ] -} -``` diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/VectorTilesConfigDocTest.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/VectorTilesConfigDocTest.java index 50dbd24008f..c0adbbd143b 100644 --- a/src/ext-test/java/org/opentripplanner/ext/vectortiles/VectorTilesConfigDocTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/VectorTilesConfigDocTest.java @@ -1,6 +1,5 @@ package org.opentripplanner.ext.vectortiles; -import static org.opentripplanner.framework.application.OtpFileNames.ROUTER_CONFIG_FILENAME; import static org.opentripplanner.framework.io.FileUtils.assertFileEquals; import static org.opentripplanner.framework.io.FileUtils.readFile; import static org.opentripplanner.framework.io.FileUtils.writeFile; @@ -8,7 +7,7 @@ import static org.opentripplanner.generate.doc.framework.DocsTestConstants.DOCS_ROOT; import static org.opentripplanner.generate.doc.framework.DocsTestConstants.TEMPLATE_ROOT; import static org.opentripplanner.generate.doc.framework.TemplateUtil.replaceSection; -import static org.opentripplanner.standalone.config.framework.json.JsonSupport.jsonNodeFromResource; +import static org.opentripplanner.standalone.config.framework.json.JsonSupport.jsonNodeFromPath; import java.io.File; import org.junit.jupiter.api.Test; @@ -19,6 +18,7 @@ import org.opentripplanner.generate.doc.framework.SkipNodes; import org.opentripplanner.standalone.config.RouterConfig; import org.opentripplanner.standalone.config.framework.json.NodeAdapter; +import org.opentripplanner.test.support.ResourceLoader; @GeneratesDocumentation public class VectorTilesConfigDocTest { @@ -27,7 +27,6 @@ public class VectorTilesConfigDocTest { private static final File TEMPLATE = new File(TEMPLATE_ROOT, DOCUMENT); private static final File OUT_FILE = new File(DOCS_ROOT, DOCUMENT); private static final SkipNodes SKIP_NODES = SkipNodes.of().build(); - private static final String ROUTER_CONFIG_PATH = "standalone/config/" + ROUTER_CONFIG_FILENAME; @Test public void updateDoc() { @@ -37,23 +36,23 @@ public void updateDoc() { String template = readFile(TEMPLATE); String original = readFile(OUT_FILE); - template = replaceSection(template, "parameters", updaterDoc(node)); + template = replaceSection(template, "parameters", vectorTilesDoc(node)); writeFile(OUT_FILE, template); assertFileEquals(original, OUT_FILE); } private NodeAdapter readVectorTiles() { - var json = jsonNodeFromResource(ROUTER_CONFIG_PATH); - var conf = new RouterConfig(json, ROUTER_CONFIG_PATH, false); + var path = ResourceLoader.of(this).file("router-config.json").toPath(); + var json = jsonNodeFromPath(path); + var conf = new RouterConfig(json, path.toString(), false); return conf.asNodeAdapter().child("vectorTiles"); } - private String updaterDoc(NodeAdapter node) { + private String vectorTilesDoc(NodeAdapter node) { DocBuilder buf = new DocBuilder(); addParameterSummaryTable(buf, node); addDetailsSection(buf, node); - addExample(buf, node); return buf.toString(); } @@ -73,8 +72,4 @@ private String getParameterDetailsTable(NodeAdapter node) { return ParameterDetailsList.listParametersWithDetails(node, SKIP_NODES, HEADER_4); } - private void addExample(DocBuilder buf, NodeAdapter node) { - buf.addSection("##### Example configuration"); - buf.addUpdaterExample(ROUTER_CONFIG_FILENAME, node.rawNode()); - } } diff --git a/src/ext/resources/org/opentripplanner/ext/vectortiles/router-config.json b/src/ext/resources/org/opentripplanner/ext/vectortiles/router-config.json new file mode 100644 index 00000000000..df325d076a3 --- /dev/null +++ b/src/ext/resources/org/opentripplanner/ext/vectortiles/router-config.json @@ -0,0 +1,16 @@ +{ + "vectorTiles": { + "basePath": "/otp_ct/vectorTiles", + "layers": [ + { + "name": "stops", + "type": "Stop", + "mapper": "Digitransit", + "maxZoom": 20, + "minZoom": 14, + "cacheMaxSeconds": 600 + } + ] + } +} + diff --git a/src/test/resources/standalone/config/router-config.json b/src/test/resources/standalone/config/router-config.json index f64a3b0f3b9..ced4564ca8a 100644 --- a/src/test/resources/standalone/config/router-config.json +++ b/src/test/resources/standalone/config/router-config.json @@ -166,6 +166,7 @@ "hideFeedId": true }, "vectorTiles": { + "basePath": "/otp_ct/vectorTiles", "layers": [ { "name": "stops", From 9ab2afd1d6d5910ea14d481c9e1626b79606985d Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 17 Jan 2024 14:00:03 +0100 Subject: [PATCH 19/69] Improve tests --- doc-templates/sandbox/MapboxVectorTilesApi.md | 3 +-- docs/RouterConfiguration.md | 1 + docs/sandbox/MapboxVectorTilesApi.md | 3 +-- .../vectortiles/VectorTilesConfigDocTest.java | 1 - .../ext/vectortiles/VectorTilesResource.java | 2 +- .../apis/support/TileJson.java | 2 +- .../GraphInspectorVectorTileResource.java | 2 +- .../apis/support/TileJsonTest.java | 27 ++++++++++++++++--- 8 files changed, 29 insertions(+), 12 deletions(-) diff --git a/doc-templates/sandbox/MapboxVectorTilesApi.md b/doc-templates/sandbox/MapboxVectorTilesApi.md index dfba427919a..7fa1fefa56d 100644 --- a/doc-templates/sandbox/MapboxVectorTilesApi.md +++ b/doc-templates/sandbox/MapboxVectorTilesApi.md @@ -3,8 +3,7 @@ ## Contact Info - HSL, Finland -- Kyyti Group Oy, Finland -- Hannes Junnila +- IBI Arcardis, US ## Documentation diff --git a/docs/RouterConfiguration.md b/docs/RouterConfiguration.md index 351c582d72d..556e672e482 100644 --- a/docs/RouterConfiguration.md +++ b/docs/RouterConfiguration.md @@ -603,6 +603,7 @@ Used to group requests when monitoring OTP. "hideFeedId" : true }, "vectorTiles" : { + "basePath" : "/otp_ct/vectorTiles", "layers" : [ { "name" : "stops", diff --git a/docs/sandbox/MapboxVectorTilesApi.md b/docs/sandbox/MapboxVectorTilesApi.md index 547eb3501c1..75ab5008124 100644 --- a/docs/sandbox/MapboxVectorTilesApi.md +++ b/docs/sandbox/MapboxVectorTilesApi.md @@ -3,8 +3,7 @@ ## Contact Info - HSL, Finland -- Kyyti Group Oy, Finland -- Hannes Junnila +- IBI Arcardis, US ## Documentation diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/VectorTilesConfigDocTest.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/VectorTilesConfigDocTest.java index c0adbbd143b..e758026d02b 100644 --- a/src/ext-test/java/org/opentripplanner/ext/vectortiles/VectorTilesConfigDocTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/VectorTilesConfigDocTest.java @@ -71,5 +71,4 @@ private void addDetailsSection(DocBuilder buf, NodeAdapter node) { private String getParameterDetailsTable(NodeAdapter node) { return ParameterDetailsList.listParametersWithDetails(node, SKIP_NODES, HEADER_4); } - } diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java b/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java index e1c119713d1..3182936b281 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java @@ -96,7 +96,7 @@ public TileJson getTileJson( TileJson.overrideBasePath(uri, headers, overrideBasePath, requestedLayers) ) .orElseGet(() -> - TileJson.defaultBasePath(uri, headers, requestedLayers, ignoreRouterId, "vectorTiles") + TileJson.defaultPath(uri, headers, requestedLayers, ignoreRouterId, "vectorTiles") ); return new TileJson(url, envelope, feedInfos); diff --git a/src/main/java/org/opentripplanner/apis/support/TileJson.java b/src/main/java/org/opentripplanner/apis/support/TileJson.java index 840542d68a8..feedf1657ef 100644 --- a/src/main/java/org/opentripplanner/apis/support/TileJson.java +++ b/src/main/java/org/opentripplanner/apis/support/TileJson.java @@ -58,7 +58,7 @@ public TileJson(String tileUrl, WorldEnvelope envelope, Collection fee center = new double[] { c.longitude(), c.latitude(), 9 }; } - public static String defaultBasePath( + public static String defaultPath( UriInfo uri, HttpHeaders headers, String layers, diff --git a/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java b/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java index ada9381ec1d..f5839cdabc2 100644 --- a/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java +++ b/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java @@ -103,7 +103,7 @@ public TileJson getTileJson( var envelope = serverContext.worldEnvelopeService().envelope().orElseThrow(); List feedInfos = feedInfos(); - var url = TileJson.defaultBasePath( + var url = TileJson.defaultPath( uri, headers, requestedLayers, diff --git a/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java b/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java index 890dc09aa92..e9a7fe39eba 100644 --- a/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java +++ b/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java @@ -4,14 +4,18 @@ import java.net.URI; import java.net.URISyntaxException; +import javax.annotation.Nonnull; import org.glassfish.jersey.internal.MapPropertiesDelegate; import org.glassfish.jersey.server.ContainerRequest; import org.glassfish.jersey.server.internal.routing.UriRoutingContext; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; class TileJsonTest { + private static final String LAYERS = "stops,rentalVehicles"; + @ParameterizedTest @ValueSource( strings = { @@ -22,12 +26,27 @@ class TileJsonTest { } ) void overrideBasePath(String basePath) throws URISyntaxException { - var uri = new URI("https://localhost:8080"); - var header = new ContainerRequest(uri, uri, "GET", null, new MapPropertiesDelegate(), null); - var uriInfo = new UriRoutingContext(header); + var req = container(); + var uriInfo = new UriRoutingContext(req); assertEquals( "https://localhost:8080/otp_ct/vectorTiles/stops,rentalVehicles/{z}/{x}/{y}.pbf", - TileJson.overrideBasePath(uriInfo, header, basePath, "stops,rentalVehicles") + TileJson.overrideBasePath(uriInfo, req, basePath, LAYERS) ); } + + @Test + void defaultPath() throws URISyntaxException { + var req = container(); + var uriInfo = new UriRoutingContext(req); + assertEquals( + "https://localhost:8080/otp/routers/default/vectorTiles/stops,rentalVehicles/{z}/{x}/{y}.pbf", + TileJson.defaultPath(uriInfo, req, LAYERS, "default", "vectorTiles") + ); + } + + @Nonnull + private static ContainerRequest container() throws URISyntaxException { + var uri = new URI("https://localhost:8080"); + return new ContainerRequest(uri, uri, "GET", null, new MapPropertiesDelegate(), null); + } } From 3f47b57d0f8b3cb40aaa49a329a10febcd87ed64 Mon Sep 17 00:00:00 2001 From: eibakke Date: Wed, 17 Jan 2024 15:43:14 +0100 Subject: [PATCH 20/69] Adds EncompassingAreaGeometry to the GroupStop and makes it queryable in the flexibleArea on the QuayType. --- .../apis/transmodel/model/stop/QuayType.java | 17 +++++++++-------- .../netex/mapping/FlexStopsMapper.java | 5 ++++- .../transit/model/site/GroupStop.java | 7 +++++++ .../transit/model/site/GroupStopBuilder.java | 19 +++++++++++++++++++ .../apis/transmodel/schema.graphql | 2 +- 5 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java index b80efab77b5..a15bf2f838e 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java @@ -380,20 +380,21 @@ public static GraphQLObjectType create( .name("flexibleArea") .description("Geometry for flexible area.") .type(GeoJSONCoordinatesScalar.getGraphQGeoJSONCoordinatesScalar()) - .dataFetcher(environment -> - ( - environment.getSource() instanceof AreaStop areaStop - ? areaStop.getGeometry().getCoordinates() - : null - ) - ) + .dataFetcher(environment -> { + if (environment.getSource() instanceof AreaStop areaStop) { + return areaStop.getGeometry().getCoordinates(); + } else if (environment.getSource() instanceof GroupStop groupStop) { + return groupStop.getEncompassingAreaGeometry().getCoordinates(); + } + return null; + }) .build() ) .field( GraphQLFieldDefinition .newFieldDefinition() .name("flexibleGroup") - .description("the Quays part of an flexible group.") + .description("the Quays part of a flexible group.") .type(GraphQLList.list(REF)) .dataFetcher(environment -> ( diff --git a/src/main/java/org/opentripplanner/netex/mapping/FlexStopsMapper.java b/src/main/java/org/opentripplanner/netex/mapping/FlexStopsMapper.java index 1e6eb1979bb..5bc8d63679a 100644 --- a/src/main/java/org/opentripplanner/netex/mapping/FlexStopsMapper.java +++ b/src/main/java/org/opentripplanner/netex/mapping/FlexStopsMapper.java @@ -62,6 +62,7 @@ StopLocation map(FlexibleStopPlace flexibleStopPlace) { List stops = new ArrayList<>(); TransitMode flexibleStopTransitMode = mapTransitMode(flexibleStopPlace); var areas = flexibleStopPlace.getAreas().getFlexibleAreaOrFlexibleAreaRefOrHailAndRideArea(); + ArrayList areaGeometries = new ArrayList<>(); for (var area : areas) { if (!(area instanceof FlexibleArea flexibleArea)) { issueStore.add( @@ -76,6 +77,7 @@ StopLocation map(FlexibleStopPlace flexibleStopPlace) { } Geometry flexibleAreaGeometry = mapGeometry(flexibleArea); + areaGeometries.add(flexibleAreaGeometry); if (shouldAddStopsFromArea(flexibleArea, flexibleStopPlace)) { stops.addAll( @@ -100,7 +102,8 @@ StopLocation map(FlexibleStopPlace flexibleStopPlace) { // get the ids for the area and stop place correct var builder = stopModelBuilder .groupStop(idFactory.createId(flexibleStopPlace.getId())) - .withName(new NonLocalizedString(flexibleStopPlace.getName().getValue())); + .withName(new NonLocalizedString(flexibleStopPlace.getName().getValue())) + .withEncompassingAreaGeometries(areaGeometries); stops.forEach(builder::addLocation); return builder.build(); } diff --git a/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java b/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java index ac3cca3dd13..f2baf84b5c3 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java +++ b/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java @@ -24,6 +24,8 @@ public class GroupStop private final I18NString name; private final GeometryCollection geometry; + private final GeometryCollection encompassingAreaGeometry; + private final WgsCoordinate centroid; GroupStop(GroupStopBuilder builder) { @@ -33,6 +35,7 @@ public class GroupStop this.geometry = builder.geometry(); this.centroid = Objects.requireNonNull(builder.centroid()); this.stopLocations = builder.stopLocations(); + this.encompassingAreaGeometry = builder.encompassingAreaGeometry(); } public static GroupStopBuilder of(FeedScopedId id, IntSupplier indexCounter) { @@ -79,6 +82,10 @@ public Geometry getGeometry() { return geometry; } + public Geometry getEncompassingAreaGeometry() { + return encompassingAreaGeometry; + } + @Override public boolean isPartOfStation() { return false; diff --git a/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java b/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java index 5e0dc596eba..b474658f5ec 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java +++ b/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java @@ -1,5 +1,6 @@ package org.opentripplanner.transit.model.site; +import java.util.ArrayList; import java.util.HashSet; import java.util.Set; import java.util.function.IntSupplier; @@ -26,6 +27,11 @@ public class GroupStopBuilder extends AbstractEntityBuilder geometries) { + this.encompassingAreaGeometry = + new GeometryCollection( + geometries.toArray(new Geometry[0]), + GeometryUtils.getGeometryFactory() + ); + return this; + } + public I18NString name() { return name; } @@ -90,6 +105,10 @@ public GeometryCollection geometry() { return geometry; } + public GeometryCollection encompassingAreaGeometry() { + return encompassingAreaGeometry; + } + public WgsCoordinate centroid() { return centroid; } diff --git a/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql b/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql index 9b49283c180..25cf95ca2f9 100644 --- a/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql +++ b/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql @@ -579,7 +579,7 @@ type Quay implements PlaceInterface { ): [EstimatedCall!]! @timingData "Geometry for flexible area." flexibleArea: Coordinates - "the Quays part of an flexible group." + "the Quays part of a flexible group." flexibleGroup: [Quay] id: ID! "List of journey patterns servicing this quay" From b4eb8de32538fb6b1c8c1c8be926b0e0ceb3e481 Mon Sep 17 00:00:00 2001 From: eibakke Date: Wed, 17 Jan 2024 15:43:14 +0100 Subject: [PATCH 21/69] Adds EncompassingAreaGeometry to the GroupStop and makes it queryable in the flexibleArea on the QuayType. --- .../apis/transmodel/model/stop/QuayType.java | 17 +++++++++-------- .../netex/mapping/FlexStopsMapper.java | 5 ++++- .../transit/model/site/GroupStop.java | 7 +++++++ .../transit/model/site/GroupStopBuilder.java | 19 +++++++++++++++++++ .../apis/transmodel/schema.graphql | 2 +- 5 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java index b80efab77b5..a15bf2f838e 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java @@ -380,20 +380,21 @@ public static GraphQLObjectType create( .name("flexibleArea") .description("Geometry for flexible area.") .type(GeoJSONCoordinatesScalar.getGraphQGeoJSONCoordinatesScalar()) - .dataFetcher(environment -> - ( - environment.getSource() instanceof AreaStop areaStop - ? areaStop.getGeometry().getCoordinates() - : null - ) - ) + .dataFetcher(environment -> { + if (environment.getSource() instanceof AreaStop areaStop) { + return areaStop.getGeometry().getCoordinates(); + } else if (environment.getSource() instanceof GroupStop groupStop) { + return groupStop.getEncompassingAreaGeometry().getCoordinates(); + } + return null; + }) .build() ) .field( GraphQLFieldDefinition .newFieldDefinition() .name("flexibleGroup") - .description("the Quays part of an flexible group.") + .description("the Quays part of a flexible group.") .type(GraphQLList.list(REF)) .dataFetcher(environment -> ( diff --git a/src/main/java/org/opentripplanner/netex/mapping/FlexStopsMapper.java b/src/main/java/org/opentripplanner/netex/mapping/FlexStopsMapper.java index 1e6eb1979bb..7e06db882f1 100644 --- a/src/main/java/org/opentripplanner/netex/mapping/FlexStopsMapper.java +++ b/src/main/java/org/opentripplanner/netex/mapping/FlexStopsMapper.java @@ -62,6 +62,7 @@ StopLocation map(FlexibleStopPlace flexibleStopPlace) { List stops = new ArrayList<>(); TransitMode flexibleStopTransitMode = mapTransitMode(flexibleStopPlace); var areas = flexibleStopPlace.getAreas().getFlexibleAreaOrFlexibleAreaRefOrHailAndRideArea(); + List areaGeometries = new ArrayList<>(); for (var area : areas) { if (!(area instanceof FlexibleArea flexibleArea)) { issueStore.add( @@ -76,6 +77,7 @@ StopLocation map(FlexibleStopPlace flexibleStopPlace) { } Geometry flexibleAreaGeometry = mapGeometry(flexibleArea); + areaGeometries.add(flexibleAreaGeometry); if (shouldAddStopsFromArea(flexibleArea, flexibleStopPlace)) { stops.addAll( @@ -100,7 +102,8 @@ StopLocation map(FlexibleStopPlace flexibleStopPlace) { // get the ids for the area and stop place correct var builder = stopModelBuilder .groupStop(idFactory.createId(flexibleStopPlace.getId())) - .withName(new NonLocalizedString(flexibleStopPlace.getName().getValue())); + .withName(new NonLocalizedString(flexibleStopPlace.getName().getValue())) + .withEncompassingAreaGeometries(areaGeometries); stops.forEach(builder::addLocation); return builder.build(); } diff --git a/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java b/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java index ac3cca3dd13..f2baf84b5c3 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java +++ b/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java @@ -24,6 +24,8 @@ public class GroupStop private final I18NString name; private final GeometryCollection geometry; + private final GeometryCollection encompassingAreaGeometry; + private final WgsCoordinate centroid; GroupStop(GroupStopBuilder builder) { @@ -33,6 +35,7 @@ public class GroupStop this.geometry = builder.geometry(); this.centroid = Objects.requireNonNull(builder.centroid()); this.stopLocations = builder.stopLocations(); + this.encompassingAreaGeometry = builder.encompassingAreaGeometry(); } public static GroupStopBuilder of(FeedScopedId id, IntSupplier indexCounter) { @@ -79,6 +82,10 @@ public Geometry getGeometry() { return geometry; } + public Geometry getEncompassingAreaGeometry() { + return encompassingAreaGeometry; + } + @Override public boolean isPartOfStation() { return false; diff --git a/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java b/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java index 5e0dc596eba..0c7b1f644d0 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java +++ b/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java @@ -1,6 +1,7 @@ package org.opentripplanner.transit.model.site; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.function.IntSupplier; import javax.annotation.Nonnull; @@ -26,6 +27,11 @@ public class GroupStopBuilder extends AbstractEntityBuilder geometries) { + this.encompassingAreaGeometry = + new GeometryCollection( + geometries.toArray(new Geometry[0]), + GeometryUtils.getGeometryFactory() + ); + return this; + } + public I18NString name() { return name; } @@ -90,6 +105,10 @@ public GeometryCollection geometry() { return geometry; } + public GeometryCollection encompassingAreaGeometry() { + return encompassingAreaGeometry; + } + public WgsCoordinate centroid() { return centroid; } diff --git a/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql b/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql index 9b49283c180..25cf95ca2f9 100644 --- a/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql +++ b/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql @@ -579,7 +579,7 @@ type Quay implements PlaceInterface { ): [EstimatedCall!]! @timingData "Geometry for flexible area." flexibleArea: Coordinates - "the Quays part of an flexible group." + "the Quays part of a flexible group." flexibleGroup: [Quay] id: ID! "List of journey patterns servicing this quay" From 7dbffd0122fa65b7bf5b0a3e03fc2c5208076153 Mon Sep 17 00:00:00 2001 From: eibakke Date: Wed, 17 Jan 2024 16:26:49 +0100 Subject: [PATCH 22/69] Adds docstring to getEncompassingAreaGeometry and getGeometry methods of the GroupStop. --- .../org/opentripplanner/transit/model/site/GroupStop.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java b/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java index f2baf84b5c3..2f2ddca044f 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java +++ b/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java @@ -77,11 +77,17 @@ public WgsCoordinate getCoordinate() { return centroid; } + /** + * Returns the geometry of all stops and areas belonging to this location group. + */ @Override public Geometry getGeometry() { return geometry; } + /** + * Returns the geometry of the area that encompasses the bounds of this location group. + */ public Geometry getEncompassingAreaGeometry() { return encompassingAreaGeometry; } From 103c498130c9845532b5075d1fbb94b6de4f4082 Mon Sep 17 00:00:00 2001 From: eibakke Date: Wed, 17 Jan 2024 16:34:21 +0100 Subject: [PATCH 23/69] Defaults encompassingAreaGeometry in GroupStopBuilder (and therefore also GroupStop) to null instead of an empty GeometryCollection. --- .../opentripplanner/transit/model/site/GroupStopBuilder.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java b/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java index 0c7b1f644d0..b574eb8c9ea 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java +++ b/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java @@ -27,10 +27,7 @@ public class GroupStopBuilder extends AbstractEntityBuilder Date: Sun, 14 Jan 2024 12:41:02 +0100 Subject: [PATCH 24/69] refactor: Code cleanup Throttle --- .../opentripplanner/framework/logging/Throttle.java | 12 ++++++++---- .../framework/logging/ThrottleTest.java | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/opentripplanner/framework/logging/Throttle.java b/src/main/java/org/opentripplanner/framework/logging/Throttle.java index 631d59a2697..ed8a2c1bef4 100644 --- a/src/main/java/org/opentripplanner/framework/logging/Throttle.java +++ b/src/main/java/org/opentripplanner/framework/logging/Throttle.java @@ -1,5 +1,6 @@ package org.opentripplanner.framework.logging; +import java.time.Duration; import org.opentripplanner.framework.time.TimeUtils; /** @@ -26,17 +27,20 @@ public class Throttle { private long timeout = Long.MIN_VALUE; private final String setupInfo; - Throttle(int quietPeriodMilliseconds) { - this.quietPeriodMilliseconds = quietPeriodMilliseconds; + /** + * Package local to be able to unit test. + */ + Throttle(Duration quietPeriod) { + this.quietPeriodMilliseconds = (int) quietPeriod.toMillis(); this.setupInfo = "(throttle " + TimeUtils.msToString(quietPeriodMilliseconds) + " interval)"; } public static Throttle ofOneSecond() { - return new Throttle(1000); + return new Throttle(Duration.ofSeconds(1)); } public static Throttle ofOneMinute() { - return new Throttle(1000 * 60); + return new Throttle(Duration.ofMinutes(1)); } public String setupInfo() { diff --git a/src/test/java/org/opentripplanner/framework/logging/ThrottleTest.java b/src/test/java/org/opentripplanner/framework/logging/ThrottleTest.java index 91f1667486d..c9155992daa 100644 --- a/src/test/java/org/opentripplanner/framework/logging/ThrottleTest.java +++ b/src/test/java/org/opentripplanner/framework/logging/ThrottleTest.java @@ -1,5 +1,6 @@ package org.opentripplanner.framework.logging; +import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -36,8 +37,8 @@ void smokeTest() { @Test @Disabled("Run this test manually") void manualTest() { - double quietPeriodMs = 50.0; - var subject = new Throttle((int) quietPeriodMs); + var quietPeriod = Duration.ofMillis(50); + var subject = new Throttle(quietPeriod); List events = createIntegerSequence(20_000_000); long start = System.currentTimeMillis(); From 1a0e3739b7c61d060348de3186bb329087ee1e6f Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Wed, 17 Jan 2024 16:58:02 +0100 Subject: [PATCH 25/69] refactor: Reduce dependency scope for PriorityGroupConfigurator This will make it simpler to build a report later --- .../transit/request/PriorityGroupConfigurator.java | 12 +++++------- .../RaptorRoutingRequestTransitDataCreator.java | 2 +- .../request/PriorityGroupConfiguratorTest.java | 12 ++++++------ 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/PriorityGroupConfigurator.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/PriorityGroupConfigurator.java index 826b9c09a13..6ef82786b99 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/PriorityGroupConfigurator.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/PriorityGroupConfigurator.java @@ -11,7 +11,7 @@ import org.opentripplanner.routing.algorithm.raptoradapter.transit.cost.grouppriority.TransitGroupPriority32n; import org.opentripplanner.routing.api.request.request.filter.TransitGroupSelect; import org.opentripplanner.transit.model.framework.FeedScopedId; -import org.opentripplanner.transit.model.network.RoutingTripPattern; +import org.opentripplanner.transit.model.network.TripPattern; /** * This class dynamically builds an index of transit-group-ids from the @@ -94,16 +94,14 @@ public static PriorityGroupConfigurator of( *

* @throws IllegalArgumentException if more than 32 group-ids are requested. */ - public int lookupTransitGroupPriorityId(RoutingTripPattern tripPattern) { + public int lookupTransitGroupPriorityId(TripPattern tripPattern) { if (!enabled || tripPattern == null) { return baseGroupId; } - var p = tripPattern.getPattern(); - for (var it : agencyMatchersIds) { - if (it.matcher().match(p)) { - var agencyId = p.getRoute().getAgency().getId(); + if (it.matcher().match(tripPattern)) { + var agencyId = tripPattern.getRoute().getAgency().getId(); int groupId = it.ids().get(agencyId); if (groupId < 0) { @@ -115,7 +113,7 @@ public int lookupTransitGroupPriorityId(RoutingTripPattern tripPattern) { } for (var it : globalMatchersIds) { - if (it.matcher.match(p)) { + if (it.matcher.match(tripPattern)) { return it.groupId(); } } 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 b8f915d6eb4..863a4ca9ae8 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 @@ -147,7 +147,7 @@ static List merge( tripPattern.getAlightingPossible(), BoardAlight.ALIGHT ), - priorityGroupConfigurator.lookupTransitGroupPriorityId(tripPattern) + priorityGroupConfigurator.lookupTransitGroupPriorityId(tripPattern.getPattern()) ) ); } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/PriorityGroupConfiguratorTest.java b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/PriorityGroupConfiguratorTest.java index cc4bb09f01e..7f974927c1b 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/PriorityGroupConfiguratorTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/PriorityGroupConfiguratorTest.java @@ -9,7 +9,7 @@ import org.junit.jupiter.api.Test; import org.opentripplanner.routing.api.request.request.filter.TransitGroupSelect; import org.opentripplanner.transit.model.basic.TransitMode; -import org.opentripplanner.transit.model.network.RoutingTripPattern; +import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.RegularStop; class PriorityGroupConfiguratorTest { @@ -60,11 +60,11 @@ class PriorityGroupConfiguratorTest { "10:00 10:10" ); - private final RoutingTripPattern railR1 = routeR1.getTripPattern().getRoutingTripPattern(); - private final RoutingTripPattern busB2 = routeB2.getTripPattern().getRoutingTripPattern(); - private final RoutingTripPattern railR3 = routeR3.getTripPattern().getRoutingTripPattern(); - private final RoutingTripPattern ferryF3 = routeF3.getTripPattern().getRoutingTripPattern(); - private final RoutingTripPattern busB3 = routeB3.getTripPattern().getRoutingTripPattern(); + private final TripPattern railR1 = routeR1.getTripPattern(); + private final TripPattern busB2 = routeB2.getTripPattern(); + private final TripPattern railR3 = routeR3.getTripPattern(); + private final TripPattern ferryF3 = routeF3.getTripPattern(); + private final TripPattern busB3 = routeB3.getTripPattern(); @Test void emptyConfigurationShouldReturnGroupZero() { From 390fe32ec826a99bc41e0cd7f96eabd84857e14a Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Wed, 17 Jan 2024 16:59:25 +0100 Subject: [PATCH 26/69] feature: Add a report for transit groups to the report API --- .../model/TransitGroupPriorityReport.java | 86 +++++++++++++++++++ .../reportapi/resource/ReportResource.java | 14 +++ 2 files changed, 100 insertions(+) create mode 100644 src/ext/java/org/opentripplanner/ext/reportapi/model/TransitGroupPriorityReport.java diff --git a/src/ext/java/org/opentripplanner/ext/reportapi/model/TransitGroupPriorityReport.java b/src/ext/java/org/opentripplanner/ext/reportapi/model/TransitGroupPriorityReport.java new file mode 100644 index 00000000000..635469cb3a2 --- /dev/null +++ b/src/ext/java/org/opentripplanner/ext/reportapi/model/TransitGroupPriorityReport.java @@ -0,0 +1,86 @@ +package org.opentripplanner.ext.reportapi.model; + +import java.util.Collection; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.stream.Collectors; +import org.opentripplanner.routing.algorithm.raptoradapter.transit.request.PriorityGroupConfigurator; +import org.opentripplanner.routing.api.request.request.TransitRequest; +import org.opentripplanner.transit.model.network.TripPattern; + +/** + * This class is used to report all transit-groups used for transit-group-priority. The report is + * useful when configuring/debugging this functionality. + *

+ * The format is pure text. + */ +public class TransitGroupPriorityReport { + + public static String build(Collection patterns, TransitRequest request) { + var c = PriorityGroupConfigurator.of( + request.priorityGroupsByAgency(), + request.priorityGroupsGlobal() + ); + + var map = new TreeMap(); + for (var it : patterns) { + int groupId = c.lookupTransitGroupPriorityId(it); + var de = map.computeIfAbsent(groupId, DebugEntity::new); + de.add( + it.getRoute().getAgency().getId().toString(), + it.getMode().name(), + it.getNetexSubmode().name() + ); + } + return ( + "TRANSIT GROUPS PRIORITY" + + map.values().stream().map(DebugEntity::toString).sorted().collect(Collectors.joining("")) + ); + } + + private static class DebugEntity { + + private final int groupId; + private final TreeMap agencies = new TreeMap<>(); + + public DebugEntity(int groupId) { + this.groupId = groupId; + } + + void add(String agency, String mode, String submode) { + agencies.computeIfAbsent(agency, AgencyEntry::new).add(mode, submode); + } + + @Override + public String toString() { + var buf = new StringBuilder("\n %#010x".formatted(groupId)); + for (var it : agencies.values()) { + buf.append("\n ").append(it.toString()); + } + return buf.toString(); + } + } + + private record AgencyEntry(String agency, TreeMap> modes) { + private AgencyEntry(String agency) { + this(agency, new TreeMap<>()); + } + + void add(String mode, String submode) { + modes.computeIfAbsent(mode, m -> new TreeSet<>()).add(submode); + } + + @Override + public String toString() { + var buf = new StringBuilder(); + for (var it : modes.entrySet()) { + buf.append(", "); + buf.append(it.getKey()); + if (!it.getValue().isEmpty()) { + buf.append(" (").append(String.join(", ", it.getValue())).append(")"); + } + } + return agency + " ~ " + buf.substring(2); + } + } +} diff --git a/src/ext/java/org/opentripplanner/ext/reportapi/resource/ReportResource.java b/src/ext/java/org/opentripplanner/ext/reportapi/resource/ReportResource.java index 6ccb728800e..a859b4ff78a 100644 --- a/src/ext/java/org/opentripplanner/ext/reportapi/resource/ReportResource.java +++ b/src/ext/java/org/opentripplanner/ext/reportapi/resource/ReportResource.java @@ -17,8 +17,10 @@ import org.opentripplanner.ext.reportapi.model.GraphReportBuilder; import org.opentripplanner.ext.reportapi.model.GraphReportBuilder.GraphStats; import org.opentripplanner.ext.reportapi.model.TransfersReport; +import org.opentripplanner.ext.reportapi.model.TransitGroupPriorityReport; import org.opentripplanner.model.transfer.TransferService; import org.opentripplanner.openstreetmap.tagmapping.OsmTagMapperSource; +import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.standalone.api.OtpServerRequestContext; import org.opentripplanner.transit.service.TransitService; @@ -33,11 +35,13 @@ public class ReportResource { private final TransferService transferService; private final TransitService transitService; + private final RouteRequest defaultRequest; @SuppressWarnings("unused") public ReportResource(@Context OtpServerRequestContext requestContext) { this.transferService = requestContext.transitService().getTransferService(); this.transitService = requestContext.transitService(); + this.defaultRequest = requestContext.defaultRouteRequest(); } @GET @@ -80,6 +84,16 @@ public Response getBicycleSafetyAsCsv( .build(); } + @GET + @Path("/transit/group/priorities") + @Produces(MediaType.TEXT_PLAIN) + public String getTransitGroupPriorities() { + return TransitGroupPriorityReport.build( + transitService.getAllTripPatterns(), + defaultRequest.journey().transit() + ); + } + @GET @Path("/graph.json") public Response stats(@Context OtpServerRequestContext serverRequestContext) { From 90eb73cea489823295bcce368a7a3a2778217ba1 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Wed, 17 Jan 2024 17:08:48 +0100 Subject: [PATCH 27/69] doc: Add sandbox report doc. --- docs/sandbox/ReportApi.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/sandbox/ReportApi.md b/docs/sandbox/ReportApi.md index fdb6c2d3146..1a0668d1740 100644 --- a/docs/sandbox/ReportApi.md +++ b/docs/sandbox/ReportApi.md @@ -32,6 +32,8 @@ This module mounts an endpoint for generating reports under `otp/report`. Availa - [German version](http://localhost:8080/otp/report/bicycle-safety.csv?osmWayPropertySet=germany) - [UK version](http://localhost:8080/otp/report/bicycle-safety.csv?osmWayPropertySet=uk) - [Finnish version](http://localhost:8080/otp/report/bicycle-safety.csv?osmWayPropertySet=finland) +- [/otp/report/transit/group/priorities](http://localhost:8080/otp/report/transit/group/priorities): + List all transit groups used for transit-group-priority (Competition neutral planning). ### Configuration From 66f3fc59f4ff247b8c521177ed2318aff9591b48 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 17 Jan 2024 16:49:52 +0100 Subject: [PATCH 28/69] Improve documentation --- doc-templates/sandbox/MapboxVectorTilesApi.md | 18 ++--- docs/sandbox/MapboxVectorTilesApi.md | 66 +++++++++++-------- .../apis/support/TileJson.java | 8 +++ .../config/routerconfig/VectorTileConfig.java | 20 +++++- 4 files changed, 71 insertions(+), 41 deletions(-) diff --git a/doc-templates/sandbox/MapboxVectorTilesApi.md b/doc-templates/sandbox/MapboxVectorTilesApi.md index 7fa1fefa56d..4e3e047fedb 100644 --- a/doc-templates/sandbox/MapboxVectorTilesApi.md +++ b/doc-templates/sandbox/MapboxVectorTilesApi.md @@ -14,6 +14,9 @@ public transit entities on the map. The tiles can be fetched from `/otp/routers/{routerId}/vectorTiles/{layers}/{z}/{x}/{y}.pbf`, where `layers` is a comma separated list of layer names from the configuration. +Maplibre/Mapbox GL JS also require a tilejson.json endpoint which is available at +`/otp/routers/{routerId}/vectorTiles/{layers}/tilejson.json`. + Translatable fields in the tiles are translated based on the `accept-language` header in requests. Currently, only the language with the highest priority from the header is used. @@ -137,14 +140,8 @@ For each layer, the configuration includes: - `VehicleRentalStation`: rental stations - `VehicleParking` - `VehicleParkingGroup` -- `mapper` which describes the mapper converting the properties from the OTP model entities to the - vector tile properties. Currently `Digitransit` is supported for all layer types. -- `minZoom` and `maxZoom` which describe the zoom levels the layer is active for. -- `cacheMaxSeconds` which sets the cache header in the response. The lowest value of the layers - included is selected. -- `expansionFactor` How far outside its boundaries should the tile contain information. The value is - a fraction of the tile size. If you are having problem with icons and shapes being clipped at tile - edges, then increase this number. + + ### Extending @@ -162,9 +159,6 @@ new `LayerType` enum as the key, and the class constructor as the value. A new mapper needs to be added every time a new layer is added. See below for information. - - - #### Creating a new mapper The mapping contains information of what data to include in the vector tiles. The mappers are @@ -172,7 +166,7 @@ defined per layer. In order to create a new mapper for a layer, you need to create a new class extending `PropertyMapper`. In that class, you need to implement the -method `Collection> map(T input)`. The type T is dependent on the layer for which +method `Collection> map(T input)`. The type T is dependent on the layer for which you implement the mapper for. It needs to return a list of attributes, as key-value pairs which will be written into the vector tile. diff --git a/docs/sandbox/MapboxVectorTilesApi.md b/docs/sandbox/MapboxVectorTilesApi.md index 75ab5008124..cfb9a634129 100644 --- a/docs/sandbox/MapboxVectorTilesApi.md +++ b/docs/sandbox/MapboxVectorTilesApi.md @@ -14,6 +14,9 @@ public transit entities on the map. The tiles can be fetched from `/otp/routers/{routerId}/vectorTiles/{layers}/{z}/{x}/{y}.pbf`, where `layers` is a comma separated list of layer names from the configuration. +Maplibre/Mapbox GL JS also require a tilejson.json endpoint which is available at +`/otp/routers/{routerId}/vectorTiles/{layers}/tilejson.json`. + Translatable fields in the tiles are translated based on the `accept-language` header in requests. Currently, only the language with the highest priority from the header is used. @@ -137,38 +140,13 @@ For each layer, the configuration includes: - `VehicleRentalStation`: rental stations - `VehicleParking` - `VehicleParkingGroup` -- `mapper` which describes the mapper converting the properties from the OTP model entities to the - vector tile properties. Currently `Digitransit` is supported for all layer types. -- `minZoom` and `maxZoom` which describe the zoom levels the layer is active for. -- `cacheMaxSeconds` which sets the cache header in the response. The lowest value of the layers - included is selected. -- `expansionFactor` How far outside its boundaries should the tile contain information. The value is - a fraction of the tile size. If you are having problem with icons and shapes being clipped at tile - edges, then increase this number. - -### Extending - -If more generic layers are created for this API, it should be moved out from the sandbox, into the -core code, with potentially leaving specific property mappers in place. - -#### Creating a new layer - -In order to create a new type of layer, you need to create a new class extending `LayerBuilder`. -You need to implement two methods, `List getGeometries(Envelope query)`, which returns a -list of geometries, with an object of type `T` as their userData in the geometry, -and `double getExpansionFactor()`, which describes how much information outside the tile bounds -should be included. This layer then needs to be added into `VectorTilesResource.layers`, with a -new `LayerType` enum as the key, and the class constructor as the value. - -A new mapper needs to be added every time a new layer is added. See below for information. - | Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | |----------------------------------------------------------------|:----------:|--------------------------------------------------------------------------------------------|:----------:|---------------|:-----:| -| basePath | `string` | TODO: Add short summary. | *Optional* | | 2.5 | +| [basePath](#vectorTiles_basePath) | `string` | The path of the vector tile source URLs in `tilejson.json`. | *Optional* | | 2.5 | | [layers](#vectorTiles_layers) | `object[]` | Configuration of the individual layers for the Mapbox vector tiles. | *Optional* | | 2.0 | |       type = "stop" | `enum` | Type of the layer. | *Required* | | 2.0 | |       [cacheMaxSeconds](#vectorTiles_layers_0_cacheMaxSeconds) | `integer` | Sets the cache header in the response. | *Optional* | `-1` | 2.0 | @@ -181,6 +159,24 @@ A new mapper needs to be added every time a new layer is added. See below for in #### Details +

basePath

+ +**Since version:** `2.5` ∙ **Type:** `string` ∙ **Cardinality:** `Optional` +**Path:** /vectorTiles + +The path of the vector tile source URLs in `tilejson.json`. + +This is useful if you have a proxy setup and rewrite the path that is passed to OTP. + +If you don't configure this optional value then the path returned in `tilejson.json` is +`/otp/routers/default/vectorTiles/layer1,layer2/{z}/{x}/{x}.pbf`. If you set a value of +`/otp_test/tiles` then the returned path changes to `/otp_test/tiles/layer1,layer2/{z}/{x}/{x}.pbf`. + +The protocol and host are read from the incoming HTTP request. If you run OTP behind a proxy +then make sure to set the headers `X-Forwarded-Proto` and `X-Forwarded-Host` to make OTP +return the protocol and host for the original request and not the proxied one. + +

layers

**Since version:** `2.0` ∙ **Type:** `object[]` ∙ **Cardinality:** `Optional` @@ -220,6 +216,22 @@ Currently `Digitransit` is supported for all layer types. +### Extending + +If more generic layers are created for this API, it should be moved out from the sandbox, into the +core code, with potentially leaving specific property mappers in place. + +#### Creating a new layer + +In order to create a new type of layer, you need to create a new class extending `LayerBuilder`. +You need to implement two methods, `List getGeometries(Envelope query)`, which returns a +list of geometries, with an object of type `T` as their userData in the geometry, +and `double getExpansionFactor()`, which describes how much information outside the tile bounds +should be included. This layer then needs to be added into `VectorTilesResource.layers`, with a +new `LayerType` enum as the key, and the class constructor as the value. + +A new mapper needs to be added every time a new layer is added. See below for information. + #### Creating a new mapper The mapping contains information of what data to include in the vector tiles. The mappers are @@ -227,7 +239,7 @@ defined per layer. In order to create a new mapper for a layer, you need to create a new class extending `PropertyMapper`. In that class, you need to implement the -method `Collection> map(T input)`. The type T is dependent on the layer for which +method `Collection> map(T input)`. The type T is dependent on the layer for which you implement the mapper for. It needs to return a list of attributes, as key-value pairs which will be written into the vector tile. diff --git a/src/main/java/org/opentripplanner/apis/support/TileJson.java b/src/main/java/org/opentripplanner/apis/support/TileJson.java index feedf1657ef..c30e4809533 100644 --- a/src/main/java/org/opentripplanner/apis/support/TileJson.java +++ b/src/main/java/org/opentripplanner/apis/support/TileJson.java @@ -58,6 +58,10 @@ public TileJson(String tileUrl, WorldEnvelope envelope, Collection fee center = new double[] { c.longitude(), c.latitude(), 9 }; } + /** + * Creates a vector source layer URL from a hard-coded path plus information from the incoming + * HTTP request. + */ public static String defaultPath( UriInfo uri, HttpHeaders headers, @@ -73,6 +77,10 @@ public static String defaultPath( ); } + /** + * Creates a vector source layer URL from a configured base path plus information from the incoming + * HTTP request. + */ public static String overrideBasePath( UriInfo uri, HttpHeaders headers, diff --git a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java index df353f40079..67fd2496e3c 100644 --- a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java @@ -9,7 +9,6 @@ import java.util.Collection; import java.util.List; -import java.util.Objects; import java.util.Optional; import javax.annotation.Nullable; import org.opentripplanner.ext.vectortiles.VectorTilesResource; @@ -50,7 +49,24 @@ public static VectorTileConfig mapVectorTilesParameters(NodeAdapter node, String .since(V2_0) .summary("Configuration of the individual layers for the Mapbox vector tiles.") .asObjects(VectorTileConfig::mapLayer), - root.of("basePath").since(V2_5).asString(DEFAULT.basePath) + root + .of("basePath") + .since(V2_5) + .summary("The path of the vector tile source URLs in `tilejson.json`.") + .description( + """ + This is useful if you have a proxy setup and rewrite the path that is passed to OTP. + + If you don't configure this optional value then the path returned in `tilejson.json` is + `/otp/routers/default/vectorTiles/layer1,layer2/{z}/{x}/{x}.pbf`. If you set a value of + `/otp_test/tiles` then the returned path changes to `/otp_test/tiles/layer1,layer2/{z}/{x}/{x}.pbf`. + + The protocol and host are read from the incoming HTTP request. If you run OTP behind a proxy + then make sure to set the headers `X-Forwarded-Proto` and `X-Forwarded-Host` to make OTP + return the protocol and host for the original request and not the proxied one. + """ + ) + .asString(DEFAULT.basePath) ); } From 7c9958b2fe10f55c626fa4bb715185f471e58eae Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 17 Jan 2024 21:10:52 +0100 Subject: [PATCH 29/69] Add test for resource --- .../vectortiles/VectorTilesResourceTest.java | 31 +++++++++++++++++++ .../opentripplanner/TestServerContext.java | 10 +++++- .../apis/support/TileJsonTest.java | 20 +++--------- .../test/support/HttpForTest.java | 18 +++++++++++ 4 files changed, 63 insertions(+), 16 deletions(-) create mode 100644 src/ext-test/java/org/opentripplanner/ext/vectortiles/VectorTilesResourceTest.java create mode 100644 src/test/java/org/opentripplanner/test/support/HttpForTest.java diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/VectorTilesResourceTest.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/VectorTilesResourceTest.java new file mode 100644 index 00000000000..ff9509a8474 --- /dev/null +++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/VectorTilesResourceTest.java @@ -0,0 +1,31 @@ +package org.opentripplanner.ext.vectortiles; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.glassfish.grizzly.http.server.Request; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.opentripplanner.TestServerContext; +import org.opentripplanner.routing.graph.Graph; +import org.opentripplanner.test.support.HttpForTest; +import org.opentripplanner.transit.service.TransitModel; + +class VectorTilesResourceTest { + + @Test + void tileJson() { + // the Grizzly request is awful to instantiate, using Mockito + var grizzlyRequest = Mockito.mock(Request.class); + var resource = new VectorTilesResource( + TestServerContext.createServerContext(new Graph(), new TransitModel()), + grizzlyRequest, + "default" + ); + var req = HttpForTest.containerRequest(); + var tileJson = resource.getTileJson(req.getUriInfo(), req, "layer1,layer2"); + assertEquals( + "https://localhost:8080/otp/routers/default/vectorTiles/layer1,layer2/{z}/{x}/{y}.pbf", + tileJson.tiles[0] + ); + } +} diff --git a/src/test/java/org/opentripplanner/TestServerContext.java b/src/test/java/org/opentripplanner/TestServerContext.java index dd640c1f000..5d74dbba240 100644 --- a/src/test/java/org/opentripplanner/TestServerContext.java +++ b/src/test/java/org/opentripplanner/TestServerContext.java @@ -16,6 +16,7 @@ import org.opentripplanner.service.worldenvelope.WorldEnvelopeService; import org.opentripplanner.service.worldenvelope.internal.DefaultWorldEnvelopeRepository; import org.opentripplanner.service.worldenvelope.internal.DefaultWorldEnvelopeService; +import org.opentripplanner.service.worldenvelope.model.WorldEnvelope; import org.opentripplanner.standalone.api.OtpServerRequestContext; import org.opentripplanner.standalone.config.RouterConfig; import org.opentripplanner.standalone.server.DefaultServerRequestContext; @@ -58,7 +59,14 @@ public static OtpServerRequestContext createServerContext( /** Static factory method to create a service for test purposes. */ public static WorldEnvelopeService createWorldEnvelopeService() { - return new DefaultWorldEnvelopeService(new DefaultWorldEnvelopeRepository()); + var repository = new DefaultWorldEnvelopeRepository(); + var envelope = WorldEnvelope + .of() + .expandToIncludeStreetEntities(0, 0) + .expandToIncludeStreetEntities(1, 1) + .build(); + repository.saveEnvelope(envelope); + return new DefaultWorldEnvelopeService(repository); } public static RealtimeVehicleService createRealtimeVehicleService(TransitService transitService) { diff --git a/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java b/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java index e9a7fe39eba..053b6ee89ef 100644 --- a/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java +++ b/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java @@ -2,15 +2,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import java.net.URI; -import java.net.URISyntaxException; -import javax.annotation.Nonnull; -import org.glassfish.jersey.internal.MapPropertiesDelegate; -import org.glassfish.jersey.server.ContainerRequest; import org.glassfish.jersey.server.internal.routing.UriRoutingContext; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import org.opentripplanner.test.support.HttpForTest; class TileJsonTest { @@ -25,8 +21,8 @@ class TileJsonTest { "///otp_ct/vectorTiles/", } ) - void overrideBasePath(String basePath) throws URISyntaxException { - var req = container(); + void overrideBasePath(String basePath) { + var req = HttpForTest.containerRequest(); var uriInfo = new UriRoutingContext(req); assertEquals( "https://localhost:8080/otp_ct/vectorTiles/stops,rentalVehicles/{z}/{x}/{y}.pbf", @@ -35,18 +31,12 @@ void overrideBasePath(String basePath) throws URISyntaxException { } @Test - void defaultPath() throws URISyntaxException { - var req = container(); + void defaultPath() { + var req = HttpForTest.containerRequest(); var uriInfo = new UriRoutingContext(req); assertEquals( "https://localhost:8080/otp/routers/default/vectorTiles/stops,rentalVehicles/{z}/{x}/{y}.pbf", TileJson.defaultPath(uriInfo, req, LAYERS, "default", "vectorTiles") ); } - - @Nonnull - private static ContainerRequest container() throws URISyntaxException { - var uri = new URI("https://localhost:8080"); - return new ContainerRequest(uri, uri, "GET", null, new MapPropertiesDelegate(), null); - } } diff --git a/src/test/java/org/opentripplanner/test/support/HttpForTest.java b/src/test/java/org/opentripplanner/test/support/HttpForTest.java new file mode 100644 index 00000000000..b130a2f3fde --- /dev/null +++ b/src/test/java/org/opentripplanner/test/support/HttpForTest.java @@ -0,0 +1,18 @@ +package org.opentripplanner.test.support; + +import java.net.URI; +import java.net.URISyntaxException; +import org.glassfish.jersey.internal.MapPropertiesDelegate; +import org.glassfish.jersey.server.ContainerRequest; + +public class HttpForTest { + + public static ContainerRequest containerRequest() { + try { + URI uri = new URI("https://localhost:8080"); + return new ContainerRequest(uri, uri, "GET", null, new MapPropertiesDelegate(), null); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } +} From 34793eb6a8e4eb9b2de25adff5f6e6cb97f684d5 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 17 Jan 2024 21:58:21 +0100 Subject: [PATCH 30/69] Rename methods --- .../opentripplanner/ext/vectortiles/VectorTilesResource.java | 4 ++-- src/main/java/org/opentripplanner/apis/support/TileJson.java | 4 ++-- .../apis/vectortiles/GraphInspectorVectorTileResource.java | 2 +- .../java/org/opentripplanner/apis/support/TileJsonTest.java | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java b/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java index 3182936b281..d87c60836de 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java @@ -93,10 +93,10 @@ public TileJson getTileJson( .vectorTileConfig() .basePath() .map(overrideBasePath -> - TileJson.overrideBasePath(uri, headers, overrideBasePath, requestedLayers) + TileJson.urlFromOverriddenBasePath(uri, headers, overrideBasePath, requestedLayers) ) .orElseGet(() -> - TileJson.defaultPath(uri, headers, requestedLayers, ignoreRouterId, "vectorTiles") + TileJson.urlWithDefaultPath(uri, headers, requestedLayers, ignoreRouterId, "vectorTiles") ); return new TileJson(url, envelope, feedInfos); diff --git a/src/main/java/org/opentripplanner/apis/support/TileJson.java b/src/main/java/org/opentripplanner/apis/support/TileJson.java index c30e4809533..09261e295e0 100644 --- a/src/main/java/org/opentripplanner/apis/support/TileJson.java +++ b/src/main/java/org/opentripplanner/apis/support/TileJson.java @@ -62,7 +62,7 @@ public TileJson(String tileUrl, WorldEnvelope envelope, Collection fee * Creates a vector source layer URL from a hard-coded path plus information from the incoming * HTTP request. */ - public static String defaultPath( + public static String urlWithDefaultPath( UriInfo uri, HttpHeaders headers, String layers, @@ -81,7 +81,7 @@ public static String defaultPath( * Creates a vector source layer URL from a configured base path plus information from the incoming * HTTP request. */ - public static String overrideBasePath( + public static String urlFromOverriddenBasePath( UriInfo uri, HttpHeaders headers, String overridePath, diff --git a/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java b/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java index f5839cdabc2..666adebbbf7 100644 --- a/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java +++ b/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java @@ -103,7 +103,7 @@ public TileJson getTileJson( var envelope = serverContext.worldEnvelopeService().envelope().orElseThrow(); List feedInfos = feedInfos(); - var url = TileJson.defaultPath( + var url = TileJson.urlWithDefaultPath( uri, headers, requestedLayers, diff --git a/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java b/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java index 053b6ee89ef..6b78042bf29 100644 --- a/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java +++ b/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java @@ -26,7 +26,7 @@ void overrideBasePath(String basePath) { var uriInfo = new UriRoutingContext(req); assertEquals( "https://localhost:8080/otp_ct/vectorTiles/stops,rentalVehicles/{z}/{x}/{y}.pbf", - TileJson.overrideBasePath(uriInfo, req, basePath, LAYERS) + TileJson.urlFromOverriddenBasePath(uriInfo, req, basePath, LAYERS) ); } @@ -36,7 +36,7 @@ void defaultPath() { var uriInfo = new UriRoutingContext(req); assertEquals( "https://localhost:8080/otp/routers/default/vectorTiles/stops,rentalVehicles/{z}/{x}/{y}.pbf", - TileJson.defaultPath(uriInfo, req, LAYERS, "default", "vectorTiles") + TileJson.urlWithDefaultPath(uriInfo, req, LAYERS, "default", "vectorTiles") ); } } From ded7050e670e3e3b5268cc81e0e489415c2a91c2 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 17 Jan 2024 22:19:17 +0100 Subject: [PATCH 31/69] Reuse helper class --- .../standalone/server/EtagRequestFilterTest.java | 11 +++-------- .../org/opentripplanner/test/support/HttpForTest.java | 8 ++++++-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/test/java/org/opentripplanner/standalone/server/EtagRequestFilterTest.java b/src/test/java/org/opentripplanner/standalone/server/EtagRequestFilterTest.java index 1451a218852..5adf8264d8e 100644 --- a/src/test/java/org/opentripplanner/standalone/server/EtagRequestFilterTest.java +++ b/src/test/java/org/opentripplanner/standalone/server/EtagRequestFilterTest.java @@ -8,7 +8,6 @@ import java.nio.charset.StandardCharsets; import java.util.stream.Stream; import javax.annotation.Nonnull; -import org.glassfish.jersey.internal.MapPropertiesDelegate; import org.glassfish.jersey.message.internal.OutboundJaxrsResponse; import org.glassfish.jersey.message.internal.OutboundMessageContext; import org.glassfish.jersey.message.internal.Statuses; @@ -17,6 +16,7 @@ import org.jets3t.service.utils.Mimetypes; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.opentripplanner.test.support.HttpForTest; import org.opentripplanner.test.support.VariableSource; class EtagRequestFilterTest { @@ -44,7 +44,7 @@ void writeEtag( byte[] entity, String expectedEtag ) throws IOException { - var request = request(method); + var request = HttpForTest.containerRequest(method); var response = response(status, request); var headers = response.getHeaders(); headers.add(EtagRequestFilter.HEADER_CONTENT_TYPE, responseContentType); @@ -65,7 +65,7 @@ void writeEtag( @VariableSource("ifNoneMatchCases") void ifNoneMatch(String ifNoneMatch, int expectedStatus, byte[] expectedEntity) throws IOException { - var request = request("GET"); + var request = HttpForTest.containerRequest("GET"); request.header(EtagRequestFilter.HEADER_IF_NONE_MATCH, ifNoneMatch); var response = response(200, request); var headers = response.getHeaders(); @@ -92,9 +92,4 @@ private static ContainerResponse response(int status, ContainerRequest request) private static byte[] bytes(String input) { return input.getBytes(StandardCharsets.UTF_8); } - - @Nonnull - private static ContainerRequest request(String method) { - return new ContainerRequest(null, null, method, null, new MapPropertiesDelegate(), null); - } } diff --git a/src/test/java/org/opentripplanner/test/support/HttpForTest.java b/src/test/java/org/opentripplanner/test/support/HttpForTest.java index b130a2f3fde..7bbe272572d 100644 --- a/src/test/java/org/opentripplanner/test/support/HttpForTest.java +++ b/src/test/java/org/opentripplanner/test/support/HttpForTest.java @@ -7,12 +7,16 @@ public class HttpForTest { - public static ContainerRequest containerRequest() { + public static ContainerRequest containerRequest(String method) { try { URI uri = new URI("https://localhost:8080"); - return new ContainerRequest(uri, uri, "GET", null, new MapPropertiesDelegate(), null); + return new ContainerRequest(uri, uri, method, null, new MapPropertiesDelegate(), null); } catch (URISyntaxException e) { throw new RuntimeException(e); } } + + public static ContainerRequest containerRequest() { + return containerRequest("GET"); + } } From b7f02fc9a6f9c9c4fc6e491f98b2a4da831b124d Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 19 Jan 2024 10:20:27 +0100 Subject: [PATCH 32/69] Update docs --- docs/sandbox/MapboxVectorTilesApi.md | 9 +++++---- .../standalone/config/routerconfig/VectorTileConfig.java | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/sandbox/MapboxVectorTilesApi.md b/docs/sandbox/MapboxVectorTilesApi.md index cfb9a634129..92cd867ecce 100644 --- a/docs/sandbox/MapboxVectorTilesApi.md +++ b/docs/sandbox/MapboxVectorTilesApi.md @@ -169,11 +169,12 @@ The path of the vector tile source URLs in `tilejson.json`. This is useful if you have a proxy setup and rewrite the path that is passed to OTP. If you don't configure this optional value then the path returned in `tilejson.json` is -`/otp/routers/default/vectorTiles/layer1,layer2/{z}/{x}/{x}.pbf`. If you set a value of -`/otp_test/tiles` then the returned path changes to `/otp_test/tiles/layer1,layer2/{z}/{x}/{x}.pbf`. +`/otp/routers/default/vectorTiles/layer1,layer2/{z}/{x}/{x}.pbf`. If you, for example, set +a value of `/otp_test/tiles` then the returned path changes to +`/otp_test/tiles/layer1,layer2/{z}/{x}/{x}.pbf`. -The protocol and host are read from the incoming HTTP request. If you run OTP behind a proxy -then make sure to set the headers `X-Forwarded-Proto` and `X-Forwarded-Host` to make OTP +The protocol and host are always read from the incoming HTTP request. If you run OTP behind +a proxy then make sure to set the headers `X-Forwarded-Proto` and `X-Forwarded-Host` to make OTP return the protocol and host for the original request and not the proxied one. diff --git a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java index 67fd2496e3c..0abc046282d 100644 --- a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java @@ -58,11 +58,12 @@ public static VectorTileConfig mapVectorTilesParameters(NodeAdapter node, String This is useful if you have a proxy setup and rewrite the path that is passed to OTP. If you don't configure this optional value then the path returned in `tilejson.json` is - `/otp/routers/default/vectorTiles/layer1,layer2/{z}/{x}/{x}.pbf`. If you set a value of - `/otp_test/tiles` then the returned path changes to `/otp_test/tiles/layer1,layer2/{z}/{x}/{x}.pbf`. + `/otp/routers/default/vectorTiles/layer1,layer2/{z}/{x}/{x}.pbf`. If you, for example, set + a value of `/otp_test/tiles` then the returned path changes to + `/otp_test/tiles/layer1,layer2/{z}/{x}/{x}.pbf`. - The protocol and host are read from the incoming HTTP request. If you run OTP behind a proxy - then make sure to set the headers `X-Forwarded-Proto` and `X-Forwarded-Host` to make OTP + The protocol and host are always read from the incoming HTTP request. If you run OTP behind + a proxy then make sure to set the headers `X-Forwarded-Proto` and `X-Forwarded-Host` to make OTP return the protocol and host for the original request and not the proxied one. """ ) From e2ba239751b9b4bd557804c9b393e2fd38828011 Mon Sep 17 00:00:00 2001 From: eibakke Date: Fri, 19 Jan 2024 15:07:11 +0100 Subject: [PATCH 33/69] Gets rid of instanceof in QuayType to differentiate between the types of StopLocation. This is done mainly by moving method signatures into the StopLocation interface from the implementing classes. --- .../opentripplanner/ext/flex/FlexIndex.java | 2 +- .../ext/flex/trip/ScheduledDeviatedTrip.java | 6 +- .../ext/flex/trip/UnscheduledTrip.java | 6 +- .../apis/transmodel/model/stop/QuayType.java | 83 ++++++------------- .../module/StreetLinkerModule.java | 2 +- .../netex/mapping/NetexMapper.java | 2 +- .../transit/model/site/AreaStop.java | 14 ++++ .../transit/model/site/GroupStop.java | 21 ++++- .../transit/model/site/GroupStopBuilder.java | 2 +- .../transit/model/site/RegularStop.java | 6 ++ .../transit/model/site/StopLocation.java | 21 +++++ .../gtfs/mapping/StopTimeMapperTest.java | 2 +- .../netex/mapping/FlexStopsMapperTest.java | 2 +- .../transit/model/site/GroupStopTest.java | 2 +- 14 files changed, 99 insertions(+), 72 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexIndex.java b/src/ext/java/org/opentripplanner/ext/flex/FlexIndex.java index 5cab995d419..a875ba0f516 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexIndex.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexIndex.java @@ -33,7 +33,7 @@ public FlexIndex(TransitModel transitModel) { tripById.put(flexTrip.getTrip().getId(), flexTrip); for (StopLocation stop : flexTrip.getStops()) { if (stop instanceof GroupStop groupStop) { - for (StopLocation stopElement : groupStop.getLocations()) { + for (StopLocation stopElement : groupStop.getChildLocations()) { flexTripsByStop.put(stopElement, flexTrip); } } else { 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 edff0860933..e16e1e5e1f7 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTrip.java @@ -248,7 +248,7 @@ public TransitBuilder copy( private Collection expandStops(StopLocation stop) { return stop instanceof GroupStop groupStop - ? groupStop.getLocations() + ? groupStop.getChildLocations() : Collections.singleton(stop); } @@ -259,7 +259,7 @@ private int getFromIndex(NearbyStop accessEgress) { } StopLocation stop = stopTimes[i].stop; if (stop instanceof GroupStop groupStop) { - if (groupStop.getLocations().contains(accessEgress.stop)) { + if (groupStop.getChildLocations().contains(accessEgress.stop)) { return i; } } else { @@ -278,7 +278,7 @@ private int getToIndex(NearbyStop accessEgress) { } StopLocation stop = stopTimes[i].stop; if (stop instanceof GroupStop groupStop) { - if (groupStop.getLocations().contains(accessEgress.stop)) { + if (groupStop.getChildLocations().contains(accessEgress.stop)) { return i; } } else { 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 71a77eee5e7..c5968507676 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java +++ b/src/ext/java/org/opentripplanner/ext/flex/trip/UnscheduledTrip.java @@ -300,7 +300,7 @@ public TransitBuilder copy() { private Stream expandStops(int index) { var stop = stopTimes[index].stop(); return stop instanceof GroupStop groupStop - ? groupStop.getLocations().stream().map(s -> new IndexedStopLocation(index, s)) + ? groupStop.getChildLocations().stream().map(s -> new IndexedStopLocation(index, s)) : Stream.of(new IndexedStopLocation(index, stop)); } @@ -311,7 +311,7 @@ private int getFromIndex(NearbyStop accessEgress) { } StopLocation stop = stopTimes[i].stop(); if (stop instanceof GroupStop groupStop) { - if (groupStop.getLocations().contains(accessEgress.stop)) { + if (groupStop.getChildLocations().contains(accessEgress.stop)) { return i; } } else { @@ -330,7 +330,7 @@ private int getToIndex(NearbyStop accessEgress) { } StopLocation stop = stopTimes[i].stop(); if (stop instanceof GroupStop groupStop) { - if (groupStop.getLocations().contains(accessEgress.stop)) { + if (groupStop.getChildLocations().contains(accessEgress.stop)) { return i; } } else { diff --git a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java index a15bf2f838e..6dd9fc5e31c 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java @@ -25,9 +25,6 @@ import org.opentripplanner.transit.model.basic.Accessibility; import org.opentripplanner.transit.model.basic.TransitMode; import org.opentripplanner.transit.model.network.TripPattern; -import org.opentripplanner.transit.model.site.AreaStop; -import org.opentripplanner.transit.model.site.GroupStop; -import org.opentripplanner.transit.model.site.RegularStop; import org.opentripplanner.transit.model.site.Station; import org.opentripplanner.transit.model.site.StopLocation; @@ -80,11 +77,8 @@ public static GraphQLObjectType create( .type(Scalars.GraphQLString) .build() ) - .dataFetcher(environment -> - ( - ((StopLocation) environment.getSource()).getName() - .toString(GqlUtil.getLocale(environment)) - ) + .dataFetcher(env -> + (((StopLocation) env.getSource()).getName().toString(GqlUtil.getLocale(env))) ) .build() ) @@ -93,7 +87,7 @@ public static GraphQLObjectType create( .newFieldDefinition() .name("latitude") .type(Scalars.GraphQLFloat) - .dataFetcher(environment -> (((StopLocation) environment.getSource()).getLat())) + .dataFetcher(env -> (((StopLocation) env.getSource()).getLat())) .build() ) .field( @@ -101,7 +95,7 @@ public static GraphQLObjectType create( .newFieldDefinition() .name("longitude") .type(Scalars.GraphQLFloat) - .dataFetcher(environment -> (((StopLocation) environment.getSource()).getLon())) + .dataFetcher(env -> (((StopLocation) env.getSource()).getLon())) .build() ) .field( @@ -109,11 +103,8 @@ public static GraphQLObjectType create( .newFieldDefinition() .name("description") .type(Scalars.GraphQLString) - .dataFetcher(environment -> - GraphQLUtils.getTranslation( - ((StopLocation) environment.getSource()).getDescription(), - environment - ) + .dataFetcher(env -> + GraphQLUtils.getTranslation(((StopLocation) env.getSource()).getDescription(), env) ) .build() ) @@ -123,12 +114,12 @@ public static GraphQLObjectType create( .name("stopPlace") .description("The stop place to which this quay belongs to.") .type(stopPlaceType) - .dataFetcher(environment -> { - Station station = ((StopLocation) environment.getSource()).getParentStation(); + .dataFetcher(env -> { + Station station = ((StopLocation) env.getSource()).getParentStation(); if (station != null) { return new MonoOrMultiModalStation( station, - GqlUtil.getTransitService(environment).getMultiModalStationForStation(station) + GqlUtil.getTransitService(env).getMultiModalStationForStation(station) ); } else { return null; @@ -142,9 +133,9 @@ public static GraphQLObjectType create( .name("wheelchairAccessible") .type(EnumTypes.WHEELCHAIR_BOARDING) .description("Whether this quay is suitable for wheelchair boarding.") - .dataFetcher(environment -> + .dataFetcher(env -> Objects.requireNonNullElse( - (((StopLocation) environment.getSource()).getWheelchairAccessibility()), + (((StopLocation) env.getSource()).getWheelchairAccessibility()), Accessibility.NO_INFORMATION ) ) @@ -155,10 +146,8 @@ public static GraphQLObjectType create( .newFieldDefinition() .name("timeZone") .type(Scalars.GraphQLString) - .dataFetcher(environment -> - Optional - .ofNullable(((StopLocation) environment.getSource()).getTimeZone()) - .map(ZoneId::getId) + .dataFetcher(env -> + Optional.ofNullable(((StopLocation) env.getSource()).getTimeZone()).map(ZoneId::getId) ) .build() ) @@ -170,7 +159,7 @@ public static GraphQLObjectType create( .description( "Public code used to identify this quay within the stop place. For instance a platform code." ) - .dataFetcher(environment -> (((StopLocation) environment.getSource()).getPlatformCode())) + .dataFetcher(env -> (((StopLocation) env.getSource()).getPlatformCode())) .build() ) .field( @@ -180,10 +169,10 @@ public static GraphQLObjectType create( .withDirective(gqlUtil.timingData) .description("List of lines servicing this quay") .type(new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(lineType)))) - .dataFetcher(environment -> + .dataFetcher(env -> GqlUtil - .getTransitService(environment) - .getPatternsForStop(environment.getSource(), true) + .getTransitService(env) + .getPatternsForStop(env.getSource(), true) .stream() .map(TripPattern::getRoute) .distinct() @@ -198,8 +187,8 @@ public static GraphQLObjectType create( .withDirective(gqlUtil.timingData) .description("List of journey patterns servicing this quay") .type(new GraphQLNonNull(new GraphQLList(journeyPatternType))) - .dataFetcher(environment -> - GqlUtil.getTransitService(environment).getPatternsForStop(environment.getSource(), true) + .dataFetcher(env -> + GqlUtil.getTransitService(env).getPatternsForStop(env.getSource(), true) ) .build() ) @@ -361,17 +350,7 @@ public static GraphQLObjectType create( .newFieldDefinition() .name("stopType") .type(Scalars.GraphQLString) - .dataFetcher(environment -> { - StopLocation stopLocation = environment.getSource(); - if (stopLocation instanceof RegularStop) { - return "regular"; - } else if (stopLocation instanceof AreaStop) { - return "flexible_area"; - } else if (stopLocation instanceof GroupStop) { - return "flexible_group"; - } - return null; - }) + .dataFetcher(env -> ((StopLocation) env.getSource()).getStopType()) .build() ) .field( @@ -380,13 +359,11 @@ public static GraphQLObjectType create( .name("flexibleArea") .description("Geometry for flexible area.") .type(GeoJSONCoordinatesScalar.getGraphQGeoJSONCoordinatesScalar()) - .dataFetcher(environment -> { - if (environment.getSource() instanceof AreaStop areaStop) { - return areaStop.getGeometry().getCoordinates(); - } else if (environment.getSource() instanceof GroupStop groupStop) { - return groupStop.getEncompassingAreaGeometry().getCoordinates(); - } - return null; + .dataFetcher(env -> { + StopLocation stopLocation = env.getSource(); + return stopLocation.getEncompassingAreaGeometry() == null + ? null + : stopLocation.getEncompassingAreaGeometry().getCoordinates(); }) .build() ) @@ -396,13 +373,7 @@ public static GraphQLObjectType create( .name("flexibleGroup") .description("the Quays part of a flexible group.") .type(GraphQLList.list(REF)) - .dataFetcher(environment -> - ( - environment.getSource() instanceof GroupStop groupStop - ? groupStop.getLocations() - : null - ) - ) + .dataFetcher(env -> ((StopLocation) env.getSource()).getChildLocations()) .build() ) .field( @@ -410,7 +381,7 @@ public static GraphQLObjectType create( .newFieldDefinition() .name("tariffZones") .type(new GraphQLNonNull(new GraphQLList(tariffZoneType))) - .dataFetcher(environment -> ((StopLocation) environment.getSource()).getFareZones()) + .dataFetcher(env -> ((StopLocation) env.getSource()).getFareZones()) .build() ) .build(); diff --git a/src/main/java/org/opentripplanner/graph_builder/module/StreetLinkerModule.java b/src/main/java/org/opentripplanner/graph_builder/module/StreetLinkerModule.java index 7ec84763d81..37334161b0a 100644 --- a/src/main/java/org/opentripplanner/graph_builder/module/StreetLinkerModule.java +++ b/src/main/java/org/opentripplanner/graph_builder/module/StreetLinkerModule.java @@ -97,7 +97,7 @@ public void linkTransitStops(Graph graph, TransitModel transitModel) { .stream() .filter(GroupStop.class::isInstance) .map(GroupStop.class::cast) - .flatMap(g -> g.getLocations().stream().filter(RegularStop.class::isInstance)) + .flatMap(g -> g.getChildLocations().stream().filter(RegularStop.class::isInstance)) .toList() ); } diff --git a/src/main/java/org/opentripplanner/netex/mapping/NetexMapper.java b/src/main/java/org/opentripplanner/netex/mapping/NetexMapper.java index 30bd04eea73..c3c9ad2d0ae 100644 --- a/src/main/java/org/opentripplanner/netex/mapping/NetexMapper.java +++ b/src/main/java/org/opentripplanner/netex/mapping/NetexMapper.java @@ -374,7 +374,7 @@ private void mapFlexibleStopPlaces() { transitBuilder.stopModel().withAreaStop(areaStop); } else if (stopLocation instanceof GroupStop groupStop) { transitBuilder.stopModel().withGroupStop(groupStop); - for (var child : groupStop.getLocations()) { + for (var child : groupStop.getChildLocations()) { if (child instanceof AreaStop areaStop) { transitBuilder.stopModel().withAreaStop(areaStop); } diff --git a/src/main/java/org/opentripplanner/transit/model/site/AreaStop.java b/src/main/java/org/opentripplanner/transit/model/site/AreaStop.java index c369c995f09..a398a7dae1c 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/AreaStop.java +++ b/src/main/java/org/opentripplanner/transit/model/site/AreaStop.java @@ -84,6 +84,12 @@ public I18NString getUrl() { return url; } + @Nonnull + @Override + public String getStopType() { + return "flexible_area"; + } + @Override public String getFirstZoneAsString() { return zoneId; @@ -103,6 +109,14 @@ public Geometry getGeometry() { return geometry; } + /** + * Returns the geometry of area that defines the stop, in this case the same as getGeometry. + */ + @Override + public Geometry getEncompassingAreaGeometry() { + return geometry; + } + @Override public boolean isPartOfStation() { return false; diff --git a/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java b/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java index 2f2ddca044f..d42a1eb121d 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java +++ b/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java @@ -63,6 +63,12 @@ public I18NString getUrl() { return null; } + @Override + @Nonnull + public String getStopType() { + return "flexible_group"; + } + @Override public String getFirstZoneAsString() { return null; @@ -86,9 +92,16 @@ public Geometry getGeometry() { } /** - * Returns the geometry of the area that encompasses the bounds of this location group. + * Returns the geometry of the area that encompasses the bounds of this StopLocation group. If the + * group is defined only as a list of stops, this will return the same as getGeometry. If on the + * other hand the group is defined as an area and the stops are inferred from that area, then this + * will return the geometry of the area. */ + @Override public Geometry getEncompassingAreaGeometry() { + if (encompassingAreaGeometry == null) { + return geometry; + } return encompassingAreaGeometry; } @@ -105,7 +118,9 @@ public boolean isPartOfSameStationAs(StopLocation alternativeStop) { /** * Returns all the locations belonging to this location group. */ - public Set getLocations() { + @Override + @Nonnull + public Set getChildLocations() { return stopLocations; } @@ -114,7 +129,7 @@ public boolean sameAs(@Nonnull GroupStop other) { return ( getId().equals(other.getId()) && Objects.equals(name, other.getName()) && - Objects.equals(stopLocations, other.getLocations()) + Objects.equals(stopLocations, other.getChildLocations()) ); } diff --git a/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java b/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java index b574eb8c9ea..0dc22d20512 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java +++ b/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java @@ -41,7 +41,7 @@ public class GroupStopBuilder extends AbstractEntityBuilder(original.getLocations()); + this.stopLocations = new HashSet<>(original.getChildLocations()); this.geometry = (GeometryCollection) original.getGeometry(); this.centroid = original.getCoordinate(); } diff --git a/src/main/java/org/opentripplanner/transit/model/site/RegularStop.java b/src/main/java/org/opentripplanner/transit/model/site/RegularStop.java index 5d5760337ff..88fafab17e8 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/RegularStop.java +++ b/src/main/java/org/opentripplanner/transit/model/site/RegularStop.java @@ -81,6 +81,12 @@ public I18NString getUrl() { return url; } + @Nonnull + @Override + public String getStopType() { + return "regular"; + } + @Override @Nullable public ZoneId getTimeZone() { diff --git a/src/main/java/org/opentripplanner/transit/model/site/StopLocation.java b/src/main/java/org/opentripplanner/transit/model/site/StopLocation.java index 84658c16be8..0d42519d663 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/StopLocation.java +++ b/src/main/java/org/opentripplanner/transit/model/site/StopLocation.java @@ -3,6 +3,7 @@ import java.time.ZoneId; import java.util.Collection; import java.util.List; +import java.util.Set; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.locationtech.jts.geom.Geometry; @@ -43,6 +44,9 @@ public interface StopLocation extends LogInfo { @Nullable I18NString getUrl(); + @Nonnull + String getStopType(); + /** * Short text or a number that identifies the location for riders. These codes are often used in * phone-based reservation systems to make it easier for riders to specify a particular location. @@ -121,6 +125,15 @@ default String getFirstZoneAsString() { @Nullable Geometry getGeometry(); + /** + * The geometry of the area that encompasses the bounds of the stop area. If the stop is defined + * as a point, this is null. + */ + @Nullable + default Geometry getEncompassingAreaGeometry() { + return null; + } + @Nullable default ZoneId getTimeZone() { return null; @@ -135,6 +148,14 @@ default StopTransferPriority getPriority() { boolean isPartOfSameStationAs(StopLocation alternativeStop); + /** + * Returns the child locations of this location, for example StopLocations within a GroupStop. + */ + @Nullable + default Set getChildLocations() { + return null; + } + @Override default String logName() { return ObjectUtils.ifNotNull(getName(), Object::toString, null); diff --git a/src/test/java/org/opentripplanner/gtfs/mapping/StopTimeMapperTest.java b/src/test/java/org/opentripplanner/gtfs/mapping/StopTimeMapperTest.java index 6e082d9e98d..94c203c76ae 100644 --- a/src/test/java/org/opentripplanner/gtfs/mapping/StopTimeMapperTest.java +++ b/src/test/java/org/opentripplanner/gtfs/mapping/StopTimeMapperTest.java @@ -228,6 +228,6 @@ public void testFlexLocationGroup() { assertInstanceOf(GroupStop.class, mapped.getStop()); var groupStop = (GroupStop) mapped.getStop(); - assertEquals("[RegularStop{A:1 Stop}]", groupStop.getLocations().toString()); + assertEquals("[RegularStop{A:1 Stop}]", groupStop.getChildLocations().toString()); } } diff --git a/src/test/java/org/opentripplanner/netex/mapping/FlexStopsMapperTest.java b/src/test/java/org/opentripplanner/netex/mapping/FlexStopsMapperTest.java index b59f3c1b58a..e4bba2b729d 100644 --- a/src/test/java/org/opentripplanner/netex/mapping/FlexStopsMapperTest.java +++ b/src/test/java/org/opentripplanner/netex/mapping/FlexStopsMapperTest.java @@ -258,7 +258,7 @@ private void assertGroupStopMapping(FlexibleStopPlace flexibleStopPlace) { assertNotNull(groupStop); // Only one of the stops should be inside the polygon - Set locations = groupStop.getLocations(); + Set locations = groupStop.getChildLocations(); assertEquals(1, locations.size()); assertEquals(stop1.getId(), locations.stream().findFirst().orElseThrow().getId()); } diff --git a/src/test/java/org/opentripplanner/transit/model/site/GroupStopTest.java b/src/test/java/org/opentripplanner/transit/model/site/GroupStopTest.java index fa073404e39..17938131eef 100644 --- a/src/test/java/org/opentripplanner/transit/model/site/GroupStopTest.java +++ b/src/test/java/org/opentripplanner/transit/model/site/GroupStopTest.java @@ -44,7 +44,7 @@ void copy() { assertEquals(subject, copy); assertEquals(ID, copy.getId().getId()); - assertEquals(STOP_LOCATION, copy.getLocations().iterator().next()); + assertEquals(STOP_LOCATION, copy.getChildLocations().iterator().next()); assertEquals("v2", copy.getName().toString()); } From dcf811e80ce793e3dba4a69cef27b8b569fe3b10 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 19 Jan 2024 16:36:27 +0100 Subject: [PATCH 34/69] Update Portland config example --- docs/examples/ibi/portland/build-config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/examples/ibi/portland/build-config.json b/docs/examples/ibi/portland/build-config.json index 4b3a232ffba..46309d21c59 100644 --- a/docs/examples/ibi/portland/build-config.json +++ b/docs/examples/ibi/portland/build-config.json @@ -6,7 +6,7 @@ "transitFeeds": [ { "type": "gtfs", - "feedId": "trimet", + "feedId": "TriMet", "source": "https://developer.trimet.org/schedule/gtfs.zip" } ] From cb59e3dd2d8982a2efde8d810322a3057910dcf0 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 22 Jan 2024 09:55:25 +0100 Subject: [PATCH 35/69] Make the layers param a List --- .../ext/vectortiles/VectorTilesResource.java | 6 ++++-- .../java/org/opentripplanner/apis/support/TileJson.java | 9 +++++---- .../vectortiles/GraphInspectorVectorTileResource.java | 3 ++- .../org/opentripplanner/apis/support/TileJsonTest.java | 3 ++- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java b/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java index d87c60836de..772db7394f3 100644 --- a/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java +++ b/src/ext/java/org/opentripplanner/ext/vectortiles/VectorTilesResource.java @@ -89,14 +89,16 @@ public TileJson getTileJson( .filter(Predicate.not(Objects::isNull)) .toList(); + List rLayers = Arrays.asList(requestedLayers.split(",")); + var url = serverContext .vectorTileConfig() .basePath() .map(overrideBasePath -> - TileJson.urlFromOverriddenBasePath(uri, headers, overrideBasePath, requestedLayers) + TileJson.urlFromOverriddenBasePath(uri, headers, overrideBasePath, rLayers) ) .orElseGet(() -> - TileJson.urlWithDefaultPath(uri, headers, requestedLayers, ignoreRouterId, "vectorTiles") + TileJson.urlWithDefaultPath(uri, headers, rLayers, ignoreRouterId, "vectorTiles") ); return new TileJson(url, envelope, feedInfos); diff --git a/src/main/java/org/opentripplanner/apis/support/TileJson.java b/src/main/java/org/opentripplanner/apis/support/TileJson.java index 09261e295e0..75aabb2b6c6 100644 --- a/src/main/java/org/opentripplanner/apis/support/TileJson.java +++ b/src/main/java/org/opentripplanner/apis/support/TileJson.java @@ -4,6 +4,7 @@ import jakarta.ws.rs.core.UriInfo; import java.io.Serializable; import java.util.Collection; +import java.util.List; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.opentripplanner.framework.io.HttpUtils; @@ -65,7 +66,7 @@ public TileJson(String tileUrl, WorldEnvelope envelope, Collection fee public static String urlWithDefaultPath( UriInfo uri, HttpHeaders headers, - String layers, + List layers, String ignoreRouterId, String path ) { @@ -73,7 +74,7 @@ public static String urlWithDefaultPath( HttpUtils.getBaseAddress(uri, headers), ignoreRouterId, path, - layers + String.join(",", layers) ); } @@ -85,14 +86,14 @@ public static String urlFromOverriddenBasePath( UriInfo uri, HttpHeaders headers, String overridePath, - String layers + List layers ) { var strippedPath = StringUtils.stripStart(overridePath, "/"); strippedPath = StringUtils.stripEnd(strippedPath, "/"); return "%s/%s/%s/{z}/{x}/{y}.pbf".formatted( HttpUtils.getBaseAddress(uri, headers), strippedPath, - layers + String.join(",", layers) ); } } diff --git a/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java b/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java index 666adebbbf7..08008b4fe82 100644 --- a/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java +++ b/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java @@ -102,11 +102,12 @@ public TileJson getTileJson( ) { var envelope = serverContext.worldEnvelopeService().envelope().orElseThrow(); List feedInfos = feedInfos(); + List rlayer = Arrays.asList(requestedLayers.split(",")); var url = TileJson.urlWithDefaultPath( uri, headers, - requestedLayers, + rlayer, ignoreRouterId, "inspector/vectortile" ); diff --git a/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java b/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java index 6b78042bf29..ac3b7bca522 100644 --- a/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java +++ b/src/test/java/org/opentripplanner/apis/support/TileJsonTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import java.util.List; import org.glassfish.jersey.server.internal.routing.UriRoutingContext; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -10,7 +11,7 @@ class TileJsonTest { - private static final String LAYERS = "stops,rentalVehicles"; + private static final List LAYERS = List.of("stops", "rentalVehicles"); @ParameterizedTest @ValueSource( From de355dd3683281ea59220b7737b2c98b071e2b60 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 22 Jan 2024 10:11:20 +0100 Subject: [PATCH 36/69] Incorporate review feedback --- doc-templates/sandbox/MapboxVectorTilesApi.md | 14 +++++++------ docs/sandbox/MapboxVectorTilesApi.md | 20 ++++++++++--------- .../vectortiles/VectorTilesConfigDocTest.java | 2 +- ...leRentalServiceDirectoryConfigDocTest.java | 2 +- .../config/routerconfig/VectorTileConfig.java | 6 +++--- .../doc/BuildConfigurationDocTest.java | 2 +- .../generate/doc/ConfigurationDocTest.java | 2 +- .../doc/FlexConfigurationDocTest.java | 2 +- .../generate/doc/GraphQLTutorialDocTest.java | 2 +- .../generate/doc/RouteRequestDocTest.java | 2 +- .../doc/RouterConfigurationDocTest.java | 2 +- .../generate/doc/RoutingModeDocTest.java | 2 +- .../generate/doc/UpdaterConfigDocTest.java | 2 +- .../generate/doc/VehicleParkingDocTest.java | 2 +- 14 files changed, 33 insertions(+), 29 deletions(-) diff --git a/doc-templates/sandbox/MapboxVectorTilesApi.md b/doc-templates/sandbox/MapboxVectorTilesApi.md index 4e3e047fedb..879ea3755d6 100644 --- a/doc-templates/sandbox/MapboxVectorTilesApi.md +++ b/doc-templates/sandbox/MapboxVectorTilesApi.md @@ -3,18 +3,19 @@ ## Contact Info - HSL, Finland -- IBI Arcardis, US +- Arcadis, US ## Documentation This API produces [Mapbox vector tiles](https://docs.mapbox.com/vector-tiles/reference/), which are -used by eg. [Digitransit-ui](https://github.com/HSLdevcom/digitransit-ui) to show information about +used by [Digitransit-ui](https://github.com/HSLdevcom/digitransit-ui) and +[`otp-react-redux`](https://github.com/opentripplanner/otp-react-redux) to show information about public transit entities on the map. The tiles can be fetched from `/otp/routers/{routerId}/vectorTiles/{layers}/{z}/{x}/{y}.pbf`, where `layers` is a comma separated list of layer names from the configuration. -Maplibre/Mapbox GL JS also require a tilejson.json endpoint which is available at +Maplibre/Mapbox GL JS also requires a tilejson.json endpoint which is available at `/otp/routers/{routerId}/vectorTiles/{layers}/tilejson.json`. Translatable fields in the tiles are translated based on the `accept-language` header in requests. @@ -37,7 +38,8 @@ The feature must be configured in `router-config.json` as follows ```JSON { - "vectorTiles": + "vectorTiles": { + "basePath": "/only/configure/if/required", "layers": [ { "name": "stops", @@ -145,8 +147,8 @@ For each layer, the configuration includes: ### Extending -If more generic layers are created for this API, it should be moved out from the sandbox, into the -core code, with potentially leaving specific property mappers in place. +If more generic layers are created for this API, the code should be moved out from the sandbox, into +the core, perhaps potentially leaving specific property mappers in place. #### Creating a new layer diff --git a/docs/sandbox/MapboxVectorTilesApi.md b/docs/sandbox/MapboxVectorTilesApi.md index 92cd867ecce..a58bd3c30f0 100644 --- a/docs/sandbox/MapboxVectorTilesApi.md +++ b/docs/sandbox/MapboxVectorTilesApi.md @@ -3,18 +3,19 @@ ## Contact Info - HSL, Finland -- IBI Arcardis, US +- Arcadis, US ## Documentation This API produces [Mapbox vector tiles](https://docs.mapbox.com/vector-tiles/reference/), which are -used by eg. [Digitransit-ui](https://github.com/HSLdevcom/digitransit-ui) to show information about +used by [Digitransit-ui](https://github.com/HSLdevcom/digitransit-ui) and +[`otp-react-redux`](https://github.com/opentripplanner/otp-react-redux) to show information about public transit entities on the map. The tiles can be fetched from `/otp/routers/{routerId}/vectorTiles/{layers}/{z}/{x}/{y}.pbf`, where `layers` is a comma separated list of layer names from the configuration. -Maplibre/Mapbox GL JS also require a tilejson.json endpoint which is available at +Maplibre/Mapbox GL JS also requires a tilejson.json endpoint which is available at `/otp/routers/{routerId}/vectorTiles/{layers}/tilejson.json`. Translatable fields in the tiles are translated based on the `accept-language` header in requests. @@ -37,7 +38,8 @@ The feature must be configured in `router-config.json` as follows ```JSON { - "vectorTiles": + "vectorTiles": { + "basePath": "/only/configure/if/required", "layers": [ { "name": "stops", @@ -168,9 +170,9 @@ The path of the vector tile source URLs in `tilejson.json`. This is useful if you have a proxy setup and rewrite the path that is passed to OTP. -If you don't configure this optional value then the path returned in `tilejson.json` is -`/otp/routers/default/vectorTiles/layer1,layer2/{z}/{x}/{x}.pbf`. If you, for example, set -a value of `/otp_test/tiles` then the returned path changes to +If you don't configure this optional value then the path returned in `tilejson.json` is in +the format `/otp/routers/default/vectorTiles/layer1,layer2/{z}/{x}/{x}.pbf`. +If you, for example, set a value of `/otp_test/tiles` then the returned path changes to `/otp_test/tiles/layer1,layer2/{z}/{x}/{x}.pbf`. The protocol and host are always read from the incoming HTTP request. If you run OTP behind @@ -219,8 +221,8 @@ Currently `Digitransit` is supported for all layer types. ### Extending -If more generic layers are created for this API, it should be moved out from the sandbox, into the -core code, with potentially leaving specific property mappers in place. +If more generic layers are created for this API, the code should be moved out from the sandbox, into +the core, perhaps potentially leaving specific property mappers in place. #### Creating a new layer diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/VectorTilesConfigDocTest.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/VectorTilesConfigDocTest.java index e758026d02b..233e3fa3737 100644 --- a/src/ext-test/java/org/opentripplanner/ext/vectortiles/VectorTilesConfigDocTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/VectorTilesConfigDocTest.java @@ -32,7 +32,7 @@ public class VectorTilesConfigDocTest { public void updateDoc() { NodeAdapter node = readVectorTiles(); - // Read and close inout file (same as output file) + // Read and close input file (same as output file) String template = readFile(TEMPLATE); String original = readFile(OUT_FILE); diff --git a/src/ext-test/java/org/opentripplanner/ext/vehiclerentalservicedirectory/generatedoc/VehicleRentalServiceDirectoryConfigDocTest.java b/src/ext-test/java/org/opentripplanner/ext/vehiclerentalservicedirectory/generatedoc/VehicleRentalServiceDirectoryConfigDocTest.java index 51f72c05e3e..4936bb4dd44 100644 --- a/src/ext-test/java/org/opentripplanner/ext/vehiclerentalservicedirectory/generatedoc/VehicleRentalServiceDirectoryConfigDocTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/vehiclerentalservicedirectory/generatedoc/VehicleRentalServiceDirectoryConfigDocTest.java @@ -37,7 +37,7 @@ public class VehicleRentalServiceDirectoryConfigDocTest { public void updateConfigurationDoc() { NodeAdapter node = readConfigDefaults(); - // Read and close inout file (same as output file) + // Read and close input file (same as output file) String doc = readFile(TEMPLATE); String original = readFile(OUT_FILE); diff --git a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java index 0abc046282d..ad2f109ac8e 100644 --- a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java @@ -57,9 +57,9 @@ public static VectorTileConfig mapVectorTilesParameters(NodeAdapter node, String """ This is useful if you have a proxy setup and rewrite the path that is passed to OTP. - If you don't configure this optional value then the path returned in `tilejson.json` is - `/otp/routers/default/vectorTiles/layer1,layer2/{z}/{x}/{x}.pbf`. If you, for example, set - a value of `/otp_test/tiles` then the returned path changes to + If you don't configure this optional value then the path returned in `tilejson.json` is in + the format `/otp/routers/default/vectorTiles/layer1,layer2/{z}/{x}/{x}.pbf`. + If you, for example, set a value of `/otp_test/tiles` then the returned path changes to `/otp_test/tiles/layer1,layer2/{z}/{x}/{x}.pbf`. The protocol and host are always read from the incoming HTTP request. If you run OTP behind diff --git a/src/test/java/org/opentripplanner/generate/doc/BuildConfigurationDocTest.java b/src/test/java/org/opentripplanner/generate/doc/BuildConfigurationDocTest.java index 287b0145292..4009a455abe 100644 --- a/src/test/java/org/opentripplanner/generate/doc/BuildConfigurationDocTest.java +++ b/src/test/java/org/opentripplanner/generate/doc/BuildConfigurationDocTest.java @@ -49,7 +49,7 @@ public class BuildConfigurationDocTest { public void updateBuildConfigurationDoc() { NodeAdapter node = readBuildConfig(); - // Read and close inout file (same as output file) + // Read and close input file (same as output file) String doc = readFile(TEMPLATE); String original = readFile(OUT_FILE); diff --git a/src/test/java/org/opentripplanner/generate/doc/ConfigurationDocTest.java b/src/test/java/org/opentripplanner/generate/doc/ConfigurationDocTest.java index 2f972e8300a..19a562d8b3f 100644 --- a/src/test/java/org/opentripplanner/generate/doc/ConfigurationDocTest.java +++ b/src/test/java/org/opentripplanner/generate/doc/ConfigurationDocTest.java @@ -36,7 +36,7 @@ public class ConfigurationDocTest { */ @Test public void updateConfigurationDoc() { - // Read and close inout file (same as output file) + // Read and close input file (same as output file) String doc = readFile(TEMPLATE); String original = readFile(OUT_FILE); diff --git a/src/test/java/org/opentripplanner/generate/doc/FlexConfigurationDocTest.java b/src/test/java/org/opentripplanner/generate/doc/FlexConfigurationDocTest.java index 2b440d7545a..fd2d7092dc5 100644 --- a/src/test/java/org/opentripplanner/generate/doc/FlexConfigurationDocTest.java +++ b/src/test/java/org/opentripplanner/generate/doc/FlexConfigurationDocTest.java @@ -33,7 +33,7 @@ public class FlexConfigurationDocTest { public void updateFlexDoc() { NodeAdapter node = readFlexConfig(); - // Read and close inout file (same as output file) + // Read and close input file (same as output file) String template = readFile(TEMPLATE); String original = readFile(OUT_FILE); diff --git a/src/test/java/org/opentripplanner/generate/doc/GraphQLTutorialDocTest.java b/src/test/java/org/opentripplanner/generate/doc/GraphQLTutorialDocTest.java index bf2b092e092..5e858ff4d61 100644 --- a/src/test/java/org/opentripplanner/generate/doc/GraphQLTutorialDocTest.java +++ b/src/test/java/org/opentripplanner/generate/doc/GraphQLTutorialDocTest.java @@ -33,7 +33,7 @@ public class GraphQLTutorialDocTest { */ @Test public void updateTutorialDoc() throws IOException { - // Read and close inout file (same as output file) + // Read and close input file (same as output file) String doc = readFile(TEMPLATE); String original = readFile(OUT_FILE); diff --git a/src/test/java/org/opentripplanner/generate/doc/RouteRequestDocTest.java b/src/test/java/org/opentripplanner/generate/doc/RouteRequestDocTest.java index 9a39b3cfa3f..76642db3e5a 100644 --- a/src/test/java/org/opentripplanner/generate/doc/RouteRequestDocTest.java +++ b/src/test/java/org/opentripplanner/generate/doc/RouteRequestDocTest.java @@ -44,7 +44,7 @@ public class RouteRequestDocTest { public void updateRouteRequestConfigurationDoc() { NodeAdapter node = readRoutingDefaults(); - // Read and close inout file (same as output file) + // Read and close input file (same as output file) String doc = readFile(TEMPLATE); String original = readFile(OUT_FILE); diff --git a/src/test/java/org/opentripplanner/generate/doc/RouterConfigurationDocTest.java b/src/test/java/org/opentripplanner/generate/doc/RouterConfigurationDocTest.java index a48374e755c..90cdd9de975 100644 --- a/src/test/java/org/opentripplanner/generate/doc/RouterConfigurationDocTest.java +++ b/src/test/java/org/opentripplanner/generate/doc/RouterConfigurationDocTest.java @@ -51,7 +51,7 @@ public class RouterConfigurationDocTest { public void updateBuildConfigurationDoc() { NodeAdapter node = readRouterConfig(); - // Read and close inout file (same as output file) + // Read and close input file (same as output file) String doc = readFile(TEMPLATE); String original = readFile(OUT_FILE); diff --git a/src/test/java/org/opentripplanner/generate/doc/RoutingModeDocTest.java b/src/test/java/org/opentripplanner/generate/doc/RoutingModeDocTest.java index e08de453630..0c6edc7e16b 100644 --- a/src/test/java/org/opentripplanner/generate/doc/RoutingModeDocTest.java +++ b/src/test/java/org/opentripplanner/generate/doc/RoutingModeDocTest.java @@ -24,7 +24,7 @@ public class RoutingModeDocTest { @Test public void updateDocs() { - // Read and close inout file (same as output file) + // Read and close input file (same as output file) String doc = readFile(TEMPLATE); String original = readFile(OUT_FILE); diff --git a/src/test/java/org/opentripplanner/generate/doc/UpdaterConfigDocTest.java b/src/test/java/org/opentripplanner/generate/doc/UpdaterConfigDocTest.java index 3d0cb547b7a..fa5abca7814 100644 --- a/src/test/java/org/opentripplanner/generate/doc/UpdaterConfigDocTest.java +++ b/src/test/java/org/opentripplanner/generate/doc/UpdaterConfigDocTest.java @@ -50,7 +50,7 @@ public class UpdaterConfigDocTest { public void updateRouterConfigurationDoc() { NodeAdapter node = readBuildConfig(); - // Read and close inout file (same as output file) + // Read and close input file (same as output file) String template = readFile(TEMPLATE); String original = readFile(OUT_FILE); diff --git a/src/test/java/org/opentripplanner/generate/doc/VehicleParkingDocTest.java b/src/test/java/org/opentripplanner/generate/doc/VehicleParkingDocTest.java index de9b921c27a..abc9ceee806 100644 --- a/src/test/java/org/opentripplanner/generate/doc/VehicleParkingDocTest.java +++ b/src/test/java/org/opentripplanner/generate/doc/VehicleParkingDocTest.java @@ -33,7 +33,7 @@ public class VehicleParkingDocTest { public void updateVehicleParkingDoc() { NodeAdapter node = readVehicleUpdaters(); - // Read and close inout file (same as output file) + // Read and close input file (same as output file) String template = readFile(TEMPLATE); String original = readFile(OUT_FILE); From b2e14f25fc70c5e775bb972483a5de1ea98b3fc0 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 22 Jan 2024 10:24:20 +0100 Subject: [PATCH 37/69] Add changelog entry --- doc-templates/sandbox/MapboxVectorTilesApi.md | 1 + docs/sandbox/MapboxVectorTilesApi.md | 1 + 2 files changed, 2 insertions(+) diff --git a/doc-templates/sandbox/MapboxVectorTilesApi.md b/doc-templates/sandbox/MapboxVectorTilesApi.md index 879ea3755d6..dfec1ed085a 100644 --- a/doc-templates/sandbox/MapboxVectorTilesApi.md +++ b/doc-templates/sandbox/MapboxVectorTilesApi.md @@ -191,3 +191,4 @@ key, and a function to create the mapper, with a `Graph` object as a parameter, * Added DigitransitRealtime for vehicle rental stations * Changed old vehicle parking mapper to be Stadtnavi * Added a new Digitransit vehicle parking mapper with no real-time information and less fields +- 2024-01-22: Make `basePath` configurable [#5627](https://github.com/opentripplanner/OpenTripPlanner/pull/5627) \ No newline at end of file diff --git a/docs/sandbox/MapboxVectorTilesApi.md b/docs/sandbox/MapboxVectorTilesApi.md index a58bd3c30f0..8b7af296228 100644 --- a/docs/sandbox/MapboxVectorTilesApi.md +++ b/docs/sandbox/MapboxVectorTilesApi.md @@ -265,3 +265,4 @@ key, and a function to create the mapper, with a `Graph` object as a parameter, * Added DigitransitRealtime for vehicle rental stations * Changed old vehicle parking mapper to be Stadtnavi * Added a new Digitransit vehicle parking mapper with no real-time information and less fields +- 2024-01-22: Make `basePath` configurable [#5627](https://github.com/opentripplanner/OpenTripPlanner/pull/5627) \ No newline at end of file From 79bd73cd45b91963a77dc9a513bd1186deeb3f08 Mon Sep 17 00:00:00 2001 From: eibakke Date: Mon, 22 Jan 2024 14:18:36 +0100 Subject: [PATCH 38/69] Adds AreaStop layer to new debug frontend --- .../src/components/MapView/MapView.tsx | 2 +- .../apis/vectortiles/DebugStyleSpec.java | 10 +++++++++ .../GraphInspectorVectorTileResource.java | 4 +++- .../apis/vectortiles/model/StyleBuilder.java | 21 +++++++++++++++++++ .../apis/vectortiles/DebugStyleSpecTest.java | 5 +++-- .../apis/vectortiles/style.json | 13 ++++++++++++ 6 files changed, 51 insertions(+), 4 deletions(-) diff --git a/client-next/src/components/MapView/MapView.tsx b/client-next/src/components/MapView/MapView.tsx index 51cb39068f8..96b4e820bae 100644 --- a/client-next/src/components/MapView/MapView.tsx +++ b/client-next/src/components/MapView/MapView.tsx @@ -75,7 +75,7 @@ export function MapView({ }} // it's unfortunate that you have to list these layers here. // maybe there is a way around it: https://github.com/visgl/react-map-gl/discussions/2343 - interactiveLayerIds={['regular-stop', 'vertex', 'edge', 'link']} + interactiveLayerIds={['regular-stop', 'area-stop', 'vertex', 'edge', 'link']} onClick={showFeaturePropPopup} // put lat/long in URL and pan to it on page reload hash={true} diff --git a/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java b/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java index f7ca564b149..f45d7d36413 100644 --- a/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java +++ b/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java @@ -52,6 +52,7 @@ public class DebugStyleSpec { static StyleSpec build( VectorSourceLayer regularStops, + VectorSourceLayer areaStops, VectorSourceLayer edges, VectorSourceLayer vertices ) { @@ -112,6 +113,15 @@ static StyleSpec build( .minZoom(15) .maxZoom(MAX_ZOOM) .intiallyHidden(), + StyleBuilder + .ofId("area-stop") + .typeFill() + .vectorSourceLayer(areaStops) + .fillColor(GREEN) + .fillOpacity(0.5f) + .fillOutlineColor(BLACK) + .minZoom(6) + .maxZoom(MAX_ZOOM), StyleBuilder .ofId("regular-stop") .typeCircle() diff --git a/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java b/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java index 5d0778eae6d..b94482af711 100644 --- a/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java +++ b/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java @@ -1,5 +1,6 @@ package org.opentripplanner.apis.vectortiles; +import static org.opentripplanner.apis.vectortiles.model.LayerType.AreaStop; import static org.opentripplanner.apis.vectortiles.model.LayerType.Edge; import static org.opentripplanner.apis.vectortiles.model.LayerType.GeofencingZones; import static org.opentripplanner.apis.vectortiles.model.LayerType.RegularStop; @@ -47,7 +48,7 @@ public class GraphInspectorVectorTileResource { private static final LayerParams REGULAR_STOPS = new LayerParams("regularStops", RegularStop); - private static final LayerParams AREA_STOPS = new LayerParams("areaStops", LayerType.AreaStop); + private static final LayerParams AREA_STOPS = new LayerParams("areaStops", AreaStop); private static final LayerParams GEOFENCING_ZONES = new LayerParams( "geofencingZones", GeofencingZones @@ -140,6 +141,7 @@ public StyleSpec getTileJson(@Context UriInfo uri, @Context HttpHeaders headers) return DebugStyleSpec.build( REGULAR_STOPS.toVectorSourceLayer(stopsSource), + AREA_STOPS.toVectorSourceLayer(stopsSource), EDGES.toVectorSourceLayer(streetSource), VERTICES.toVectorSourceLayer(streetSource) ); diff --git a/src/main/java/org/opentripplanner/apis/vectortiles/model/StyleBuilder.java b/src/main/java/org/opentripplanner/apis/vectortiles/model/StyleBuilder.java index 3b2f36d3156..07efe376968 100644 --- a/src/main/java/org/opentripplanner/apis/vectortiles/model/StyleBuilder.java +++ b/src/main/java/org/opentripplanner/apis/vectortiles/model/StyleBuilder.java @@ -40,6 +40,7 @@ public enum LayerType { Circle, Line, Raster, + Fill, } private StyleBuilder(String id) { @@ -88,6 +89,11 @@ public StyleBuilder typeLine() { return this; } + public StyleBuilder typeFill() { + type(LayerType.Fill); + return this; + } + private StyleBuilder type(LayerType type) { props.put(TYPE, type.name().toLowerCase()); return this; @@ -132,6 +138,21 @@ public StyleBuilder lineWidth(ZoomDependentNumber zoomStops) { return this; } + public StyleBuilder fillColor(String color) { + paint.put("fill-color", validateColor(color)); + return this; + } + + public StyleBuilder fillOpacity(float opacity) { + paint.put("fill-opacity", opacity); + return this; + } + + public StyleBuilder fillOutlineColor(String color) { + paint.put("fill-outline-color", validateColor(color)); + return this; + } + /** * Hide this layer when the debug client starts. It can be made visible in the UI later. */ diff --git a/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java b/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java index befd34a3b38..f2c3ebf49de 100644 --- a/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java +++ b/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java @@ -15,10 +15,11 @@ class DebugStyleSpecTest { @Test void spec() { var vectorSource = new VectorSource("vectorSource", "https://example.com"); - var stops = new VectorSourceLayer(vectorSource, "stops"); + var regularStops = new VectorSourceLayer(vectorSource, "stops"); + var areaStops = new VectorSourceLayer(vectorSource, "stops"); var edges = new VectorSourceLayer(vectorSource, "edges"); var vertices = new VectorSourceLayer(vectorSource, "vertices"); - var spec = DebugStyleSpec.build(stops, edges, vertices); + var spec = DebugStyleSpec.build(regularStops, areaStops, edges, vertices); var json = ObjectMappers.ignoringExtraFields().valueToTree(spec); var expectation = RESOURCES.fileToString("style.json"); diff --git a/src/test/resources/org/opentripplanner/apis/vectortiles/style.json b/src/test/resources/org/opentripplanner/apis/vectortiles/style.json index 9555f32c1e5..e62c3968924 100644 --- a/src/test/resources/org/opentripplanner/apis/vectortiles/style.json +++ b/src/test/resources/org/opentripplanner/apis/vectortiles/style.json @@ -141,6 +141,19 @@ "visibility" : "none" } }, + { + "id" : "area-stop", + "type" : "fill", + "source" : "vectorSource", + "source-layer" : "stops", + "minzoom" : 6, + "maxzoom" : 23, + "paint" : { + "fill-color" : "#22DD9E", + "fill-opacity" : 0.5, + "fill-outline-color" : "#140d0e" + } + }, { "id" : "regular-stop", "type" : "circle", From 696c587e679169437a7c4f17a179f763ed7e0fed Mon Sep 17 00:00:00 2001 From: eibakke Date: Mon, 22 Jan 2024 15:17:17 +0100 Subject: [PATCH 39/69] Makes the ChildLocations of a GroupStop a List instead of a Set. --- .../opentripplanner/transit/model/site/GroupStop.java | 6 +++--- .../transit/model/site/GroupStopBuilder.java | 11 +++++------ .../transit/model/site/StopLocation.java | 3 +-- .../netex/mapping/FlexStopsMapperTest.java | 2 +- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java b/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java index d42a1eb121d..c5aa3fa028f 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java +++ b/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java @@ -1,7 +1,7 @@ package org.opentripplanner.transit.model.site; +import java.util.List; import java.util.Objects; -import java.util.Set; import java.util.function.IntSupplier; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -20,7 +20,7 @@ public class GroupStop implements StopLocation { private final int index; - private final Set stopLocations; + private final List stopLocations; private final I18NString name; private final GeometryCollection geometry; @@ -120,7 +120,7 @@ public boolean isPartOfSameStationAs(StopLocation alternativeStop) { */ @Override @Nonnull - public Set getChildLocations() { + public List getChildLocations() { return stopLocations; } diff --git a/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java b/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java index 0dc22d20512..8873e6ede99 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java +++ b/src/main/java/org/opentripplanner/transit/model/site/GroupStopBuilder.java @@ -1,8 +1,7 @@ package org.opentripplanner.transit.model.site; -import java.util.HashSet; +import java.util.ArrayList; import java.util.List; -import java.util.Set; import java.util.function.IntSupplier; import javax.annotation.Nonnull; import org.locationtech.jts.geom.Envelope; @@ -20,7 +19,7 @@ public class GroupStopBuilder extends AbstractEntityBuilder stopLocations = new HashSet<>(); + private List stopLocations = new ArrayList<>(); private GeometryCollection geometry = new GeometryCollection( null, @@ -41,7 +40,7 @@ public class GroupStopBuilder extends AbstractEntityBuilder(original.getChildLocations()); + this.stopLocations = new ArrayList<>(original.getChildLocations()); this.geometry = (GeometryCollection) original.getGeometry(); this.centroid = original.getCoordinate(); } @@ -94,8 +93,8 @@ public GroupStopBuilder addLocation(StopLocation location) { return this; } - public Set stopLocations() { - return Set.copyOf(stopLocations); + public List stopLocations() { + return List.copyOf(stopLocations); } public GeometryCollection geometry() { diff --git a/src/main/java/org/opentripplanner/transit/model/site/StopLocation.java b/src/main/java/org/opentripplanner/transit/model/site/StopLocation.java index 0d42519d663..bff327302af 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/StopLocation.java +++ b/src/main/java/org/opentripplanner/transit/model/site/StopLocation.java @@ -3,7 +3,6 @@ import java.time.ZoneId; import java.util.Collection; import java.util.List; -import java.util.Set; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.locationtech.jts.geom.Geometry; @@ -152,7 +151,7 @@ default StopTransferPriority getPriority() { * Returns the child locations of this location, for example StopLocations within a GroupStop. */ @Nullable - default Set getChildLocations() { + default List getChildLocations() { return null; } diff --git a/src/test/java/org/opentripplanner/netex/mapping/FlexStopsMapperTest.java b/src/test/java/org/opentripplanner/netex/mapping/FlexStopsMapperTest.java index e4bba2b729d..3167d64e766 100644 --- a/src/test/java/org/opentripplanner/netex/mapping/FlexStopsMapperTest.java +++ b/src/test/java/org/opentripplanner/netex/mapping/FlexStopsMapperTest.java @@ -258,7 +258,7 @@ private void assertGroupStopMapping(FlexibleStopPlace flexibleStopPlace) { assertNotNull(groupStop); // Only one of the stops should be inside the polygon - Set locations = groupStop.getChildLocations(); + List locations = groupStop.getChildLocations(); assertEquals(1, locations.size()); assertEquals(stop1.getId(), locations.stream().findFirst().orElseThrow().getId()); } From e6d30052860ebb0c750419dd7d0e679769939ec8 Mon Sep 17 00:00:00 2001 From: eibakke Date: Mon, 22 Jan 2024 15:56:38 +0100 Subject: [PATCH 40/69] Makes the getEncompassingAreaGeometry method return Optional instead of being nullable. --- .../apis/transmodel/model/stop/QuayType.java | 4 ++-- .../org/opentripplanner/transit/model/site/AreaStop.java | 5 +++-- .../org/opentripplanner/transit/model/site/GroupStop.java | 7 ++++--- .../opentripplanner/transit/model/site/StopLocation.java | 6 +++--- .../opentripplanner/netex/mapping/FlexStopsMapperTest.java | 1 - 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java index 6dd9fc5e31c..74a2d0c153e 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java @@ -361,9 +361,9 @@ public static GraphQLObjectType create( .type(GeoJSONCoordinatesScalar.getGraphQGeoJSONCoordinatesScalar()) .dataFetcher(env -> { StopLocation stopLocation = env.getSource(); - return stopLocation.getEncompassingAreaGeometry() == null + return stopLocation.getEncompassingAreaGeometry().isEmpty() ? null - : stopLocation.getEncompassingAreaGeometry().getCoordinates(); + : stopLocation.getEncompassingAreaGeometry().get().getCoordinates(); }) .build() ) diff --git a/src/main/java/org/opentripplanner/transit/model/site/AreaStop.java b/src/main/java/org/opentripplanner/transit/model/site/AreaStop.java index a398a7dae1c..41a522f595a 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/AreaStop.java +++ b/src/main/java/org/opentripplanner/transit/model/site/AreaStop.java @@ -1,6 +1,7 @@ package org.opentripplanner.transit.model.site; import java.util.Objects; +import java.util.Optional; import java.util.function.IntSupplier; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -113,8 +114,8 @@ public Geometry getGeometry() { * Returns the geometry of area that defines the stop, in this case the same as getGeometry. */ @Override - public Geometry getEncompassingAreaGeometry() { - return geometry; + public Optional getEncompassingAreaGeometry() { + return Optional.of(geometry); } @Override diff --git a/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java b/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java index c5aa3fa028f..fa23c8999ef 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java +++ b/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java @@ -2,6 +2,7 @@ import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.function.IntSupplier; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -98,11 +99,11 @@ public Geometry getGeometry() { * will return the geometry of the area. */ @Override - public Geometry getEncompassingAreaGeometry() { + public Optional getEncompassingAreaGeometry() { if (encompassingAreaGeometry == null) { - return geometry; + return Optional.of(geometry); } - return encompassingAreaGeometry; + return Optional.of(encompassingAreaGeometry); } @Override diff --git a/src/main/java/org/opentripplanner/transit/model/site/StopLocation.java b/src/main/java/org/opentripplanner/transit/model/site/StopLocation.java index bff327302af..1e4a1cc4033 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/StopLocation.java +++ b/src/main/java/org/opentripplanner/transit/model/site/StopLocation.java @@ -3,6 +3,7 @@ import java.time.ZoneId; import java.util.Collection; import java.util.List; +import java.util.Optional; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.locationtech.jts.geom.Geometry; @@ -128,9 +129,8 @@ default String getFirstZoneAsString() { * The geometry of the area that encompasses the bounds of the stop area. If the stop is defined * as a point, this is null. */ - @Nullable - default Geometry getEncompassingAreaGeometry() { - return null; + default Optional getEncompassingAreaGeometry() { + return Optional.empty(); } @Nullable diff --git a/src/test/java/org/opentripplanner/netex/mapping/FlexStopsMapperTest.java b/src/test/java/org/opentripplanner/netex/mapping/FlexStopsMapperTest.java index 3167d64e766..7529ae52a34 100644 --- a/src/test/java/org/opentripplanner/netex/mapping/FlexStopsMapperTest.java +++ b/src/test/java/org/opentripplanner/netex/mapping/FlexStopsMapperTest.java @@ -9,7 +9,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; -import java.util.Set; import net.opengis.gml._3.AbstractRingPropertyType; import net.opengis.gml._3.DirectPositionListType; import net.opengis.gml._3.LinearRingType; From 5c419e5d7e1a275cb84e0eb1dd700c9271088616 Mon Sep 17 00:00:00 2001 From: Eivind Morris Bakke Date: Tue, 23 Jan 2024 09:12:02 +0100 Subject: [PATCH 41/69] Update src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java Co-authored-by: Leonard Ehrenfried --- .../opentripplanner/apis/transmodel/model/stop/QuayType.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java index 74a2d0c153e..cc5a9baf6e4 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java @@ -361,9 +361,7 @@ public static GraphQLObjectType create( .type(GeoJSONCoordinatesScalar.getGraphQGeoJSONCoordinatesScalar()) .dataFetcher(env -> { StopLocation stopLocation = env.getSource(); - return stopLocation.getEncompassingAreaGeometry().isEmpty() - ? null - : stopLocation.getEncompassingAreaGeometry().get().getCoordinates(); + return stopLocation.getEncompassingAreaGeometry().map(g -> g.getCoordinates()).orElse(null); }) .build() ) From f446f3e941f18dc2f35e734d563c50e2c5f8502f Mon Sep 17 00:00:00 2001 From: Eivind Morris Bakke Date: Tue, 23 Jan 2024 09:12:22 +0100 Subject: [PATCH 42/69] Update src/main/java/org/opentripplanner/transit/model/site/GroupStop.java Co-authored-by: Leonard Ehrenfried --- .../org/opentripplanner/transit/model/site/GroupStop.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java b/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java index fa23c8999ef..2ee6e98a2c6 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java +++ b/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java @@ -100,10 +100,7 @@ public Geometry getGeometry() { */ @Override public Optional getEncompassingAreaGeometry() { - if (encompassingAreaGeometry == null) { - return Optional.of(geometry); - } - return Optional.of(encompassingAreaGeometry); + return Optional.ofNullable(encompassingGeometry).or(Optional.of(geometry)); } @Override From f27c900069089584519f7cb1f629b520cbd06386 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 22 Jan 2024 18:32:28 +0100 Subject: [PATCH 43/69] Introduce new path for Transmodel API --- .../opentripplanner/apis/APIEndpoints.java | 2 + .../apis/transmodel/TransmodelAPI.java | 41 ++++++++----------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/APIEndpoints.java b/src/main/java/org/opentripplanner/apis/APIEndpoints.java index 68f6bda3d3a..959815f1716 100644 --- a/src/main/java/org/opentripplanner/apis/APIEndpoints.java +++ b/src/main/java/org/opentripplanner/apis/APIEndpoints.java @@ -54,6 +54,8 @@ private APIEndpoints() { // scheduled to be removed and only here for backwards compatibility addIfEnabled(GtfsGraphQlApi, GtfsGraphQLAPI.GtfsGraphQLAPIOldPath.class); addIfEnabled(TransmodelGraphQlApi, TransmodelAPI.class); + // scheduled to be removed and only here for backwards compatibility + addIfEnabled(TransmodelGraphQlApi, TransmodelAPI.TransmodelAPIOldPath.class); // Sandbox extension APIs addIfEnabled(ActuatorAPI, ActuatorAPI.class); diff --git a/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java b/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java index 6af4ab1953c..5944fb2d2c4 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java @@ -6,7 +6,6 @@ import jakarta.ws.rs.BadRequestException; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DefaultValue; -import jakarta.ws.rs.GET; import jakarta.ws.rs.HeaderParam; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; @@ -22,6 +21,7 @@ import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; +import org.opentripplanner.apis.gtfs.GtfsGraphQLAPI; import org.opentripplanner.apis.transmodel.mapping.TransitIdMapper; import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.routing.api.request.RouteRequest; @@ -30,11 +30,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -// TODO move to org.opentripplanner.api.resource, this is a Jersey resource class - -@Path("/routers/{ignoreRouterId}/transmodel/index") -// It would be nice to get rid of the final /index. -@Produces(MediaType.APPLICATION_JSON) // One @Produces annotation for all endpoints. +@Path("/transmodel/v3") +@Produces(MediaType.APPLICATION_JSON) public class TransmodelAPI { @SuppressWarnings("unused") @@ -48,17 +45,26 @@ public class TransmodelAPI { private final ObjectMapper deserializer = new ObjectMapper(); public TransmodelAPI( - @Context OtpServerRequestContext serverContext, - /** - * @deprecated The support for multiple routers are removed from OTP2. - * See https://github.com/opentripplanner/OpenTripPlanner/issues/2760 - */ - @Deprecated @PathParam("ignoreRouterId") String ignoreRouterId + @Context OtpServerRequestContext serverContext ) { this.serverContext = serverContext; this.index = new TransmodelGraph(schema); } + /** + * This class is only here for backwards-compatibility. It will be removed in the future. + */ + @Path("/routers/{ignoreRouterId}/transmodel/index/graphql") + public static class TransmodelAPIOldPath extends GtfsGraphQLAPI { + + public TransmodelAPIOldPath( + @Context OtpServerRequestContext serverContext, + @PathParam("ignoreRouterId") String ignore + ) { + super(serverContext); + } + } + /** * This method should be called BEFORE the Web-Container is started and load new instances of this * class. This is a hack, and it would be better if the configuration was done more explicit and @@ -77,17 +83,7 @@ public static void setUp( schema = TransmodelGraphQLSchema.create(defaultRouteRequest, gqlUtil); } - /** - * Return 200 when service is loaded. - */ - @GET - @Path("/live") - public Response isAlive() { - return Response.status(Response.Status.NO_CONTENT).build(); - } - @POST - @Path("/graphql") @Consumes(MediaType.APPLICATION_JSON) public Response getGraphQL( HashMap queryParameters, @@ -130,7 +126,6 @@ public Response getGraphQL( } @POST - @Path("/graphql") @Consumes("application/graphql") public Response getGraphQL( String query, From d434086fda090e0fafda3971c245d47d2ff86da6 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 23 Jan 2024 12:45:52 +0100 Subject: [PATCH 44/69] Simplify Transmodel API path --- docs/apis/TransmodelApi.md | 5 ++--- src/client/graphiql/index.html | 2 +- .../opentripplanner/apis/transmodel/TransmodelAPI.java | 8 ++------ 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/docs/apis/TransmodelApi.md b/docs/apis/TransmodelApi.md index ce772734276..5a669b8cae5 100644 --- a/docs/apis/TransmodelApi.md +++ b/docs/apis/TransmodelApi.md @@ -13,12 +13,11 @@ Transmodel (NeTEx) with some limitations/simplification. It provides both a rout Entur provides a [GraphQL explorer](https://api.entur.io/graphql-explorer) where you may browse the GraphQL schema and try your own queries. -When running OTP locally the endpoint is available at: `http://localhost:8080/otp/routers/default/transmodel/index/graphql` +When running OTP locally the endpoint is available at: `http://localhost:8080/otp/transmodel/v3` ### Configuration -To turn this API off, add the feature `TransmodelGraphQlApi : false` in _otp-config.json_. - +To turn this API off, add the feature `TransmodelGraphQlApi : false` in `otp-config.json`. ## Changelog - old diff --git a/src/client/graphiql/index.html b/src/client/graphiql/index.html index d96f736b287..0e8d4afd1ea 100644 --- a/src/client/graphiql/index.html +++ b/src/client/graphiql/index.html @@ -153,7 +153,7 @@ let apiFlavor = parameters.flavor || "gtfs"; let urls = { gtfs: '/otp/gtfs/v1', - transmodel: '/otp/routers/default/transmodel/index/graphql' + transmodel: '/otp/transmodel/v3' } let defaultQueries = { diff --git a/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java b/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java index 5944fb2d2c4..3df6e1d6a51 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java @@ -21,7 +21,6 @@ import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; -import org.opentripplanner.apis.gtfs.GtfsGraphQLAPI; import org.opentripplanner.apis.transmodel.mapping.TransitIdMapper; import org.opentripplanner.apis.transmodel.support.GqlUtil; import org.opentripplanner.routing.api.request.RouteRequest; @@ -34,7 +33,6 @@ @Produces(MediaType.APPLICATION_JSON) public class TransmodelAPI { - @SuppressWarnings("unused") private static final Logger LOG = LoggerFactory.getLogger(TransmodelAPI.class); private static GraphQLSchema schema; @@ -44,9 +42,7 @@ public class TransmodelAPI { private final TransmodelGraph index; private final ObjectMapper deserializer = new ObjectMapper(); - public TransmodelAPI( - @Context OtpServerRequestContext serverContext - ) { + public TransmodelAPI(@Context OtpServerRequestContext serverContext) { this.serverContext = serverContext; this.index = new TransmodelGraph(schema); } @@ -55,7 +51,7 @@ public TransmodelAPI( * This class is only here for backwards-compatibility. It will be removed in the future. */ @Path("/routers/{ignoreRouterId}/transmodel/index/graphql") - public static class TransmodelAPIOldPath extends GtfsGraphQLAPI { + public static class TransmodelAPIOldPath extends TransmodelAPI { public TransmodelAPIOldPath( @Context OtpServerRequestContext serverContext, From 81c8fcd74ce1606be8f7142f5c581e3d0e86c138 Mon Sep 17 00:00:00 2001 From: eibakke Date: Tue, 23 Jan 2024 15:54:54 +0100 Subject: [PATCH 45/69] Makes the getEncompassingAreaGeometry in StopLocation return an Optional in order to allow returns of both GeometryCollection and Geometry. --- .../apis/transmodel/model/stop/QuayType.java | 6 +++++- .../org/opentripplanner/transit/model/site/GroupStop.java | 4 ++-- .../opentripplanner/transit/model/site/StopLocation.java | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java index cc5a9baf6e4..a8390e23197 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java @@ -15,6 +15,7 @@ import java.util.Collection; import java.util.Objects; import java.util.Optional; +import org.locationtech.jts.geom.Geometry; import org.opentripplanner.apis.transmodel.model.EnumTypes; import org.opentripplanner.apis.transmodel.model.plan.JourneyWhiteListed; import org.opentripplanner.apis.transmodel.model.scalars.GeoJSONCoordinatesScalar; @@ -361,7 +362,10 @@ public static GraphQLObjectType create( .type(GeoJSONCoordinatesScalar.getGraphQGeoJSONCoordinatesScalar()) .dataFetcher(env -> { StopLocation stopLocation = env.getSource(); - return stopLocation.getEncompassingAreaGeometry().map(g -> g.getCoordinates()).orElse(null); + return stopLocation + .getEncompassingAreaGeometry() + .map(Geometry::getCoordinates) + .orElse(null); }) .build() ) diff --git a/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java b/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java index 2ee6e98a2c6..20a5afb4070 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java +++ b/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java @@ -99,8 +99,8 @@ public Geometry getGeometry() { * will return the geometry of the area. */ @Override - public Optional getEncompassingAreaGeometry() { - return Optional.ofNullable(encompassingGeometry).or(Optional.of(geometry)); + public Optional getEncompassingAreaGeometry() { + return Optional.ofNullable(encompassingAreaGeometry).or(() -> Optional.of(geometry)); } @Override diff --git a/src/main/java/org/opentripplanner/transit/model/site/StopLocation.java b/src/main/java/org/opentripplanner/transit/model/site/StopLocation.java index 1e4a1cc4033..1f2ca33d460 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/StopLocation.java +++ b/src/main/java/org/opentripplanner/transit/model/site/StopLocation.java @@ -129,7 +129,7 @@ default String getFirstZoneAsString() { * The geometry of the area that encompasses the bounds of the stop area. If the stop is defined * as a point, this is null. */ - default Optional getEncompassingAreaGeometry() { + default Optional getEncompassingAreaGeometry() { return Optional.empty(); } From 31a621b3d71b4db00a83768e4b7526f1709a263d Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Tue, 23 Jan 2024 15:19:23 +0100 Subject: [PATCH 46/69] Fix: Make pass-trough override transit-group-priority --- .../transit/mappers/RaptorRequestMapper.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapper.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapper.java index 5f3b4b13746..c46e5a907cc 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapper.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapper.java @@ -119,12 +119,14 @@ private RaptorRequest doMap() { builder.withMultiCriteria(mcBuilder -> { var pt = preferences.transit(); var r = pt.raptor(); - if (!pt.relaxTransitGroupPriority().isNormal()) { - mcBuilder.withTransitPriorityCalculator(TransitGroupPriority32n.priorityCalculator()); - mcBuilder.withRelaxC1(mapRelaxCost(pt.relaxTransitGroupPriority())); - } else { + + // Note! If a pass-through-point exists, then the transit-group-priority feature is disabled + if (!request.getPassThroughPoints().isEmpty()) { mcBuilder.withPassThroughPoints(mapPassThroughPoints()); r.relaxGeneralizedCostAtDestination().ifPresent(mcBuilder::withRelaxCostAtDestination); + } else if (!pt.relaxTransitGroupPriority().isNormal()) { + mcBuilder.withTransitPriorityCalculator(TransitGroupPriority32n.priorityCalculator()); + mcBuilder.withRelaxC1(mapRelaxCost(pt.relaxTransitGroupPriority())); } }); From 3a37e98b8c0bec5af50480096c84997ff9a5d18c Mon Sep 17 00:00:00 2001 From: eibakke Date: Tue, 23 Jan 2024 16:08:50 +0100 Subject: [PATCH 47/69] Introduces the StopType Enum and StopTypeMapper for the Transmodel GraphQL API. --- .../apis/transmodel/model/stop/QuayType.java | 2 +- .../transmodel/model/stop/StopTypeMapper.java | 15 +++++++++++++++ .../transit/model/site/AreaStop.java | 4 ++-- .../transit/model/site/GroupStop.java | 4 ++-- .../transit/model/site/RegularStop.java | 4 ++-- .../transit/model/site/StopLocation.java | 2 +- .../transit/model/site/StopType.java | 7 +++++++ .../apis/transmodel/schema.graphql | 8 +++++++- 8 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopTypeMapper.java create mode 100644 src/main/java/org/opentripplanner/transit/model/site/StopType.java diff --git a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java index a8390e23197..46b09956eb2 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java @@ -350,7 +350,7 @@ public static GraphQLObjectType create( GraphQLFieldDefinition .newFieldDefinition() .name("stopType") - .type(Scalars.GraphQLString) + .type(StopTypeMapper.STOP_TYPE) .dataFetcher(env -> ((StopLocation) env.getSource()).getStopType()) .build() ) diff --git a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopTypeMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopTypeMapper.java new file mode 100644 index 00000000000..4725f5ac4f9 --- /dev/null +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopTypeMapper.java @@ -0,0 +1,15 @@ +package org.opentripplanner.apis.transmodel.model.stop; + +import graphql.schema.GraphQLEnumType; +import org.opentripplanner.transit.model.site.StopType; + +public class StopTypeMapper { + + public static final GraphQLEnumType STOP_TYPE = GraphQLEnumType + .newEnum() + .name("StopType") + .value("regular", StopType.REGULAR) + .value("flexible_area", StopType.FLEXIBLE_AREA) + .value("flexible_group", StopType.FLEXIBLE_GROUP) + .build(); +} diff --git a/src/main/java/org/opentripplanner/transit/model/site/AreaStop.java b/src/main/java/org/opentripplanner/transit/model/site/AreaStop.java index 41a522f595a..35576e0c42f 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/AreaStop.java +++ b/src/main/java/org/opentripplanner/transit/model/site/AreaStop.java @@ -87,8 +87,8 @@ public I18NString getUrl() { @Nonnull @Override - public String getStopType() { - return "flexible_area"; + public StopType getStopType() { + return StopType.FLEXIBLE_AREA; } @Override diff --git a/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java b/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java index 20a5afb4070..edee00e27e1 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java +++ b/src/main/java/org/opentripplanner/transit/model/site/GroupStop.java @@ -66,8 +66,8 @@ public I18NString getUrl() { @Override @Nonnull - public String getStopType() { - return "flexible_group"; + public StopType getStopType() { + return StopType.FLEXIBLE_GROUP; } @Override diff --git a/src/main/java/org/opentripplanner/transit/model/site/RegularStop.java b/src/main/java/org/opentripplanner/transit/model/site/RegularStop.java index 88fafab17e8..4c1638e7bae 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/RegularStop.java +++ b/src/main/java/org/opentripplanner/transit/model/site/RegularStop.java @@ -83,8 +83,8 @@ public I18NString getUrl() { @Nonnull @Override - public String getStopType() { - return "regular"; + public StopType getStopType() { + return StopType.REGULAR; } @Override diff --git a/src/main/java/org/opentripplanner/transit/model/site/StopLocation.java b/src/main/java/org/opentripplanner/transit/model/site/StopLocation.java index 1f2ca33d460..a3cbd1a8014 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/StopLocation.java +++ b/src/main/java/org/opentripplanner/transit/model/site/StopLocation.java @@ -45,7 +45,7 @@ public interface StopLocation extends LogInfo { I18NString getUrl(); @Nonnull - String getStopType(); + StopType getStopType(); /** * Short text or a number that identifies the location for riders. These codes are often used in diff --git a/src/main/java/org/opentripplanner/transit/model/site/StopType.java b/src/main/java/org/opentripplanner/transit/model/site/StopType.java new file mode 100644 index 00000000000..29a859fdd1c --- /dev/null +++ b/src/main/java/org/opentripplanner/transit/model/site/StopType.java @@ -0,0 +1,7 @@ +package org.opentripplanner.transit.model.site; + +public enum StopType { + REGULAR, + FLEXIBLE_AREA, + FLEXIBLE_GROUP, +} diff --git a/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql b/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql index 25cf95ca2f9..f0053e2a806 100644 --- a/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql +++ b/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql @@ -600,7 +600,7 @@ type Quay implements PlaceInterface { situations: [PtSituationElement!]! "The stop place to which this quay belongs to." stopPlace: StopPlace - stopType: String + stopType: StopType tariffZones: [TariffZone]! timeZone: String "Whether this quay is suitable for wheelchair boarding." @@ -1697,6 +1697,12 @@ enum StopCondition { startPoint } +enum StopType { + flexible_area + flexible_group + regular +} + enum StreetMode { "Bike only. This can be used as access/egress, but transfers will still be walk only." bicycle From 65e47e61ce7d998d7fddcf4c099df88871176a88 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Tue, 23 Jan 2024 17:04:38 +0100 Subject: [PATCH 48/69] test: Add unit test for pass-through-points in RaptorRequestMapper --- .../raptoradapter/router/TransitRouter.java | 2 +- .../transit/mappers/RaptorRequestMapper.java | 27 ++++---- .../mappers/RaptorRequestMapperTest.java | 61 +++++++++++++++++++ 3 files changed, 77 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/router/TransitRouter.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/router/TransitRouter.java index 1b5c836c832..c9e7f92263f 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/router/TransitRouter.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/router/TransitRouter.java @@ -121,7 +121,7 @@ private TransitRouterResult route() { ); // Prepare transit search - var raptorRequest = RaptorRequestMapper.mapRequest( + var raptorRequest = RaptorRequestMapper.mapRequest( request, transitSearchTimeZero, serverContext.raptorConfig().isMultiThreaded(), diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapper.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapper.java index c46e5a907cc..91547b1f62f 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapper.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapper.java @@ -12,6 +12,7 @@ import org.opentripplanner.raptor.api.model.GeneralizedCostRelaxFunction; import org.opentripplanner.raptor.api.model.RaptorAccessEgress; import org.opentripplanner.raptor.api.model.RaptorConstants; +import org.opentripplanner.raptor.api.model.RaptorTripSchedule; import org.opentripplanner.raptor.api.model.RelaxFunction; import org.opentripplanner.raptor.api.request.DebugRequestBuilder; import org.opentripplanner.raptor.api.request.Optimization; @@ -28,7 +29,7 @@ import org.opentripplanner.routing.api.request.framework.CostLinearFunction; import org.opentripplanner.transit.model.site.StopLocation; -public class RaptorRequestMapper { +public class RaptorRequestMapper { private final RouteRequest request; private final Collection accessPaths; @@ -56,7 +57,7 @@ private RaptorRequestMapper( this.meterRegistry = meterRegistry; } - public static RaptorRequest mapRequest( + public static RaptorRequest mapRequest( RouteRequest request, ZonedDateTime transitSearchTimeZero, boolean isMultiThreaded, @@ -65,7 +66,7 @@ public static RaptorRequest mapRequest( Duration searchWindowAccessSlack, MeterRegistry meterRegistry ) { - return new RaptorRequestMapper( + return new RaptorRequestMapper( request, isMultiThreaded, accessPaths, @@ -77,8 +78,8 @@ public static RaptorRequest mapRequest( .doMap(); } - private RaptorRequest doMap() { - var builder = new RaptorRequestBuilder(); + private RaptorRequest doMap() { + var builder = new RaptorRequestBuilder(); var searchParams = builder.searchParams(); var preferences = request.preferences(); @@ -176,13 +177,15 @@ private RaptorRequest doMap() { } // Add this last, it depends on generating an alias from the set values - builder.performanceTimers( - new PerformanceTimersForRaptor( - builder.generateAlias(), - preferences.system().tags(), - meterRegistry - ) - ); + if (meterRegistry != null) { + builder.performanceTimers( + new PerformanceTimersForRaptor( + builder.generateAlias(), + preferences.system().tags(), + meterRegistry + ) + ); + } return builder.build(); } diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapperTest.java b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapperTest.java index 11c59030180..89348be5c89 100644 --- a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapperTest.java +++ b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RaptorRequestMapperTest.java @@ -1,15 +1,33 @@ package org.opentripplanner.routing.algorithm.raptoradapter.transit.mappers; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import java.time.Duration; +import java.time.ZonedDateTime; import java.util.List; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.opentripplanner.raptor._data.transit.TestAccessEgress; +import org.opentripplanner.raptor._data.transit.TestTripSchedule; +import org.opentripplanner.raptor.api.model.RaptorAccessEgress; +import org.opentripplanner.raptor.api.request.RaptorRequest; +import org.opentripplanner.routing.api.request.PassThroughPoint; +import org.opentripplanner.routing.api.request.RouteRequest; import org.opentripplanner.routing.api.request.framework.CostLinearFunction; +import org.opentripplanner.transit.model._data.TransitModelForTest; +import org.opentripplanner.transit.model.site.StopLocation; class RaptorRequestMapperTest { + private static final TransitModelForTest TEST_MODEL = TransitModelForTest.of(); + private static final StopLocation STOP_A = TEST_MODEL.stop("Stop:A").build(); + private static final List ACCESS = List.of(TestAccessEgress.walk(12, 45)); + private static final List EGRESS = List.of(TestAccessEgress.walk(144, 54)); + private static final Duration D0s = Duration.ofSeconds(0); + private static final CostLinearFunction R1 = CostLinearFunction.of("50 + 1.0x"); private static final CostLinearFunction R2 = CostLinearFunction.of("0 + 1.5x"); private static final CostLinearFunction R3 = CostLinearFunction.of("30 + 2.0x"); @@ -33,4 +51,47 @@ void mapRelaxCost(CostLinearFunction input, int cost, int expected) { var calcCost = RaptorRequestMapper.mapRelaxCost(input); assertEquals(expected, calcCost.relax(cost)); } + + @Test + void testPassThroughPoints() { + var req = new RouteRequest(); + + req.setPassThroughPoints(List.of(new PassThroughPoint(List.of(STOP_A), "Via A"))); + + var result = map(req); + + assertTrue(result.multiCriteria().hasPassThroughPoints()); + assertEquals( + "[(Via A, stops: " + STOP_A.getIndex() + ")]", + result.multiCriteria().passThroughPoints().toString() + ); + } + + @Test + void testPassThroughPointsTurnTransitGroupPriorityOff() { + var req = new RouteRequest(); + + // Set pass-through and relax transit-group-priority + req.setPassThroughPoints(List.of(new PassThroughPoint(List.of(STOP_A), "Via A"))); + req.withPreferences(p -> + p.withTransit(t -> t.withRelaxTransitGroupPriority(CostLinearFunction.of("30m + 1.2t"))) + ); + + var result = map(req); + + // transit-group-priority CANNOT be used with pass-through and is turned off... + assertTrue(result.multiCriteria().transitPriorityCalculator().isEmpty()); + } + + private static RaptorRequest map(RouteRequest request) { + return RaptorRequestMapper.mapRequest( + request, + ZonedDateTime.now(), + false, + ACCESS, + EGRESS, + D0s, + null + ); + } } From d31a84e986ef4ef25aa8fee84092b41de36a3ea7 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 24 Jan 2024 10:21:20 +0100 Subject: [PATCH 49/69] Update docs/apis/TransmodelApi.md Co-authored-by: Thomas Gran --- docs/apis/TransmodelApi.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/apis/TransmodelApi.md b/docs/apis/TransmodelApi.md index 5a669b8cae5..c6d3a16a99c 100644 --- a/docs/apis/TransmodelApi.md +++ b/docs/apis/TransmodelApi.md @@ -15,6 +15,8 @@ queries. When running OTP locally the endpoint is available at: `http://localhost:8080/otp/transmodel/v3` +Note! Version `v1` and `v2` does not exist in the main OTP git repository, but in the (Entur fork)[https://github.com/entur/OpenTripPlanner] from which this code originate from. + ### Configuration To turn this API off, add the feature `TransmodelGraphQlApi : false` in `otp-config.json`. From 6d0780928917705dbccf4659e050a30bfcc8be35 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 24 Jan 2024 10:22:59 +0100 Subject: [PATCH 50/69] Improve documentation --- docs/apis/TransmodelApi.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/apis/TransmodelApi.md b/docs/apis/TransmodelApi.md index c6d3a16a99c..6f99847798a 100644 --- a/docs/apis/TransmodelApi.md +++ b/docs/apis/TransmodelApi.md @@ -15,7 +15,8 @@ queries. When running OTP locally the endpoint is available at: `http://localhost:8080/otp/transmodel/v3` -Note! Version `v1` and `v2` does not exist in the main OTP git repository, but in the (Entur fork)[https://github.com/entur/OpenTripPlanner] from which this code originate from. +**Note!** Versions `v1` and `v2` do not exist in the main OTP git repository, but in +the [Entur fork](https://github.com/entur/OpenTripPlanner) from which this code originates from. ### Configuration From 6a087d15e2baf48bac7038dba8d6c81eacc2e5e1 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 24 Jan 2024 10:53:24 +0100 Subject: [PATCH 51/69] Clarify documentation --- docs/RouterConfiguration.md | 2 +- docs/sandbox/MapboxVectorTilesApi.md | 4 ++++ .../standalone/config/routerconfig/VectorTileConfig.java | 6 +++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/RouterConfiguration.md b/docs/RouterConfiguration.md index be4be9d34ff..62fb5d9617a 100644 --- a/docs/RouterConfiguration.md +++ b/docs/RouterConfiguration.md @@ -67,7 +67,7 @@ A full list of them can be found in the [RouteRequest](RouteRequest.md). |    [hideFeedId](#transmodelApi_hideFeedId) | `boolean` | Hide the FeedId in all API output, and add it to input. | *Optional* | `false` | na | |    [tracingHeaderTags](#transmodelApi_tracingHeaderTags) | `string[]` | Used to group requests when monitoring OTP. | *Optional* | | na | | [updaters](UpdaterConfig.md) | `object[]` | Configuration for the updaters that import various types of data into OTP. | *Optional* | | 1.5 | -| [vectorTiles](sandbox/MapboxVectorTilesApi.md) | `object` | TODO: Add short summary. | *Optional* | | na | +| [vectorTiles](sandbox/MapboxVectorTilesApi.md) | `object` | Vector tile configuration | *Optional* | | na | | [vehicleRentalServiceDirectory](sandbox/VehicleRentalServiceDirectory.md) | `object` | Configuration for the vehicle rental service directory. | *Optional* | | 2.0 | diff --git a/docs/sandbox/MapboxVectorTilesApi.md b/docs/sandbox/MapboxVectorTilesApi.md index 8b7af296228..da9fd1120e1 100644 --- a/docs/sandbox/MapboxVectorTilesApi.md +++ b/docs/sandbox/MapboxVectorTilesApi.md @@ -179,6 +179,10 @@ The protocol and host are always read from the incoming HTTP request. If you run a proxy then make sure to set the headers `X-Forwarded-Proto` and `X-Forwarded-Host` to make OTP return the protocol and host for the original request and not the proxied one. +**Note:** This does _not_ change the path that OTP itself serves the tiles or `tilejson.json` +responses but simply changes the URLs listed in `tilejson.json`. The rewriting of the path +is expected to be handled by a proxy. +

layers

diff --git a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java index ad2f109ac8e..6f7d6967ce8 100644 --- a/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java +++ b/src/main/java/org/opentripplanner/standalone/config/routerconfig/VectorTileConfig.java @@ -42,7 +42,7 @@ public Optional basePath() { } public static VectorTileConfig mapVectorTilesParameters(NodeAdapter node, String paramName) { - var root = node.of(paramName).asObject(); + var root = node.of(paramName).summary("Vector tile configuration").asObject(); return new VectorTileConfig( root .of("layers") @@ -65,6 +65,10 @@ public static VectorTileConfig mapVectorTilesParameters(NodeAdapter node, String The protocol and host are always read from the incoming HTTP request. If you run OTP behind a proxy then make sure to set the headers `X-Forwarded-Proto` and `X-Forwarded-Host` to make OTP return the protocol and host for the original request and not the proxied one. + + **Note:** This does _not_ change the path that OTP itself serves the tiles or `tilejson.json` + responses but simply changes the URLs listed in `tilejson.json`. The rewriting of the path + is expected to be handled by a proxy. """ ) .asString(DEFAULT.basePath) From 264ab35db7ccb53db042ea0256f1f2f09a6f73bd Mon Sep 17 00:00:00 2001 From: eibakke Date: Wed, 24 Jan 2024 16:11:57 +0100 Subject: [PATCH 52/69] Adds documentation to the new enums and mapper. --- .../transmodel/model/stop/StopTypeMapper.java | 17 ++++++++++++++--- .../transit/model/site/StopType.java | 12 ++++++++++++ .../apis/transmodel/schema.graphql | 3 +++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopTypeMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopTypeMapper.java index 4725f5ac4f9..bde676bec59 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopTypeMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopTypeMapper.java @@ -3,13 +3,24 @@ import graphql.schema.GraphQLEnumType; import org.opentripplanner.transit.model.site.StopType; +/** + * Maps the StopType enum to a GraphQL enum. + */ public class StopTypeMapper { public static final GraphQLEnumType STOP_TYPE = GraphQLEnumType .newEnum() .name("StopType") - .value("regular", StopType.REGULAR) - .value("flexible_area", StopType.FLEXIBLE_AREA) - .value("flexible_group", StopType.FLEXIBLE_GROUP) + .value("regular", StopType.REGULAR, "A regular stop defined geographically as a point.") + .value( + "flexible_area", + StopType.FLEXIBLE_AREA, + "Boarding and alighting is allowed anywhere within the geographic area of this stop." + ) + .value( + "flexible_group", + StopType.FLEXIBLE_GROUP, + "A stop that consists of multiple other stops, area or regular." + ) .build(); } diff --git a/src/main/java/org/opentripplanner/transit/model/site/StopType.java b/src/main/java/org/opentripplanner/transit/model/site/StopType.java index 29a859fdd1c..69f11bb6b39 100644 --- a/src/main/java/org/opentripplanner/transit/model/site/StopType.java +++ b/src/main/java/org/opentripplanner/transit/model/site/StopType.java @@ -1,7 +1,19 @@ package org.opentripplanner.transit.model.site; +/** + * The type of a stop location. + */ public enum StopType { + /** + * A regular stop defined geographically as a point. + */ REGULAR, + /** + * Boarding and alighting is allowed anywhere within the geographic area of this stop. + */ FLEXIBLE_AREA, + /** + * A stop that consists of multiple other stops, area or regular. + */ FLEXIBLE_GROUP, } diff --git a/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql b/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql index f0053e2a806..a1e971d66ef 100644 --- a/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql +++ b/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql @@ -1698,8 +1698,11 @@ enum StopCondition { } enum StopType { + "Boarding and alighting is allowed anywhere within the geographic area of this stop." flexible_area + "A stop that consists of multiple other stops, area or regular." flexible_group + "A regular stop defined geographically as a point." regular } From d72ebf043c02d1a68591ae2bf59ebbad150aa49d Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Wed, 24 Jan 2024 19:07:39 +0000 Subject: [PATCH 53/69] Add changelog entry for #5613 [ci skip] --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index 6f27f60d947..4cfb1176773 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -78,6 +78,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Add new path for GTFS GraphQL API, remove batch feature [#5581](https://github.com/opentripplanner/OpenTripPlanner/pull/5581) - Restructure walk/bicycle/car preferences in router-config.json [#5582](https://github.com/opentripplanner/OpenTripPlanner/pull/5582) - Revert REST API spelling change of real-time [#5629](https://github.com/opentripplanner/OpenTripPlanner/pull/5629) +- Remove `FareComponent` [#5613](https://github.com/opentripplanner/OpenTripPlanner/pull/5613) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.4.0 (2023-09-13) From d0c552bffc56642a2dc9c279780875378325bf04 Mon Sep 17 00:00:00 2001 From: OTP Serialization Version Bot Date: Wed, 24 Jan 2024 19:07:57 +0000 Subject: [PATCH 54/69] Bump serialization version id for #5613 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 34f4365b580..3f7fc0dd2bb 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ - 137 + 138 30.1 2.50 From fa33a47dfe7423a2cab56f70d899b77d7c7c38fb Mon Sep 17 00:00:00 2001 From: eibakke Date: Thu, 25 Jan 2024 13:20:55 +0100 Subject: [PATCH 55/69] Changes the StopType field in the GraphQL API from enum to String. This allows for backward compatibility. --- .../apis/transmodel/model/stop/QuayType.java | 6 +++-- .../transmodel/model/stop/StopTypeMapper.java | 25 ++++++------------- .../apis/transmodel/schema.graphql | 11 +------- 3 files changed, 13 insertions(+), 29 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java index 46b09956eb2..0b22086dfaf 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/QuayType.java @@ -350,8 +350,10 @@ public static GraphQLObjectType create( GraphQLFieldDefinition .newFieldDefinition() .name("stopType") - .type(StopTypeMapper.STOP_TYPE) - .dataFetcher(env -> ((StopLocation) env.getSource()).getStopType()) + .type(Scalars.GraphQLString) + .dataFetcher(env -> + StopTypeMapper.getStopType(((StopLocation) env.getSource()).getStopType()) + ) .build() ) .field( diff --git a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopTypeMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopTypeMapper.java index bde676bec59..e94347b72e5 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopTypeMapper.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/stop/StopTypeMapper.java @@ -1,26 +1,17 @@ package org.opentripplanner.apis.transmodel.model.stop; -import graphql.schema.GraphQLEnumType; import org.opentripplanner.transit.model.site.StopType; /** - * Maps the StopType enum to a GraphQL enum. + * Maps the StopType enum to a String used in the GraphQL API. */ public class StopTypeMapper { - public static final GraphQLEnumType STOP_TYPE = GraphQLEnumType - .newEnum() - .name("StopType") - .value("regular", StopType.REGULAR, "A regular stop defined geographically as a point.") - .value( - "flexible_area", - StopType.FLEXIBLE_AREA, - "Boarding and alighting is allowed anywhere within the geographic area of this stop." - ) - .value( - "flexible_group", - StopType.FLEXIBLE_GROUP, - "A stop that consists of multiple other stops, area or regular." - ) - .build(); + public static String getStopType(StopType stopType) { + return switch (stopType) { + case REGULAR -> "regular"; + case FLEXIBLE_AREA -> "flexible_area"; + case FLEXIBLE_GROUP -> "flexible_group"; + }; + } } diff --git a/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql b/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql index a1e971d66ef..25cf95ca2f9 100644 --- a/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql +++ b/src/main/resources/org/opentripplanner/apis/transmodel/schema.graphql @@ -600,7 +600,7 @@ type Quay implements PlaceInterface { situations: [PtSituationElement!]! "The stop place to which this quay belongs to." stopPlace: StopPlace - stopType: StopType + stopType: String tariffZones: [TariffZone]! timeZone: String "Whether this quay is suitable for wheelchair boarding." @@ -1697,15 +1697,6 @@ enum StopCondition { startPoint } -enum StopType { - "Boarding and alighting is allowed anywhere within the geographic area of this stop." - flexible_area - "A stop that consists of multiple other stops, area or regular." - flexible_group - "A regular stop defined geographically as a point." - regular -} - enum StreetMode { "Bike only. This can be used as access/egress, but transfers will still be walk only." bicycle From 1696118f2cec9ab721436586456f7a5038e6c812 Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Thu, 25 Jan 2024 12:43:12 +0000 Subject: [PATCH 56/69] Add changelog entry for #5636 [ci skip] --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index 4cfb1176773..981f453fced 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -79,6 +79,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Restructure walk/bicycle/car preferences in router-config.json [#5582](https://github.com/opentripplanner/OpenTripPlanner/pull/5582) - Revert REST API spelling change of real-time [#5629](https://github.com/opentripplanner/OpenTripPlanner/pull/5629) - Remove `FareComponent` [#5613](https://github.com/opentripplanner/OpenTripPlanner/pull/5613) +- Add AreaStop layer to new debug frontend [#5636](https://github.com/opentripplanner/OpenTripPlanner/pull/5636) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.4.0 (2023-09-13) From 317960b34986fbf689fb2653e2283166177d1983 Mon Sep 17 00:00:00 2001 From: OTP Bot Date: Thu, 25 Jan 2024 12:44:17 +0000 Subject: [PATCH 57/69] Upgrade debug client to version 2024/01/2024-01-25T12: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 e9443e240c4..2653fdf36c2 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 fa484cbc519ccf93557ba96ee821a29ebf56066e Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Thu, 25 Jan 2024 21:33:39 +0000 Subject: [PATCH 58/69] Add changelog entry for #5627 [ci skip] --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index 981f453fced..7fc6a512c7a 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -80,6 +80,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Revert REST API spelling change of real-time [#5629](https://github.com/opentripplanner/OpenTripPlanner/pull/5629) - Remove `FareComponent` [#5613](https://github.com/opentripplanner/OpenTripPlanner/pull/5613) - Add AreaStop layer to new debug frontend [#5636](https://github.com/opentripplanner/OpenTripPlanner/pull/5636) +- Allow configuration of vector tiles base path [#5627](https://github.com/opentripplanner/OpenTripPlanner/pull/5627) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.4.0 (2023-09-13) From f38447c98f37215702300ce91f2e54ba56cab9c1 Mon Sep 17 00:00:00 2001 From: OTP Serialization Version Bot Date: Thu, 25 Jan 2024 21:33:56 +0000 Subject: [PATCH 59/69] Bump serialization version id for #5627 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3f7fc0dd2bb..c4737cc592b 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ - 138 + 139 30.1 2.50 From 3b9dd5b438db2baa068fb8ca4bf59b20edd38c2c Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Fri, 26 Jan 2024 11:39:55 +0100 Subject: [PATCH 60/69] fix: Log trip and pattern id when negative trip-times occurs in routing. --- .../framework/lang/ObjectUtils.java | 13 ++++++++++++ .../framework/tostring/ToStringBuilder.java | 14 +++++++++++-- .../request/TripScheduleWithOffset.java | 4 +++- .../model/network/RoutingTripPattern.java | 2 +- .../framework/lang/ObjectUtilsTest.java | 13 ++++++++++++ .../tostring/ToStringBuilderTest.java | 20 +++++++++++++++++++ 6 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/opentripplanner/framework/lang/ObjectUtils.java b/src/main/java/org/opentripplanner/framework/lang/ObjectUtils.java index 1e67b8f253e..a3f18748987 100644 --- a/src/main/java/org/opentripplanner/framework/lang/ObjectUtils.java +++ b/src/main/java/org/opentripplanner/framework/lang/ObjectUtils.java @@ -1,6 +1,7 @@ package org.opentripplanner.framework.lang; import java.util.function.Function; +import java.util.function.Supplier; import javax.annotation.Nullable; /** @@ -33,6 +34,18 @@ public static T ifNotNull( return ifNotNull(getter.apply(entity), defaultValue); } + /** + * Get the value or {@code null}, ignore any exceptions. This is useful if you must traverse + * a long call-chain like {@code a.b().c().d()...} when e.g. logging. + */ + public static T safeGetOrNull(Supplier body) { + try { + return body.get(); + } catch (Exception ignore) { + return null; + } + } + public static T requireNotInitialized(T oldValue, T newValue) { return requireNotInitialized(null, oldValue, newValue); } diff --git a/src/main/java/org/opentripplanner/framework/tostring/ToStringBuilder.java b/src/main/java/org/opentripplanner/framework/tostring/ToStringBuilder.java index cb5d26294db..6480b6f1187 100644 --- a/src/main/java/org/opentripplanner/framework/tostring/ToStringBuilder.java +++ b/src/main/java/org/opentripplanner/framework/tostring/ToStringBuilder.java @@ -13,9 +13,11 @@ import java.util.Collection; import java.util.Objects; import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.Collectors; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import org.opentripplanner.framework.lang.ObjectUtils; import org.opentripplanner.framework.lang.OtpNumberFormat; import org.opentripplanner.framework.time.DurationUtils; import org.opentripplanner.framework.time.TimeUtils; @@ -134,12 +136,20 @@ public ToStringBuilder addObj(String name, Object value, @Nullable Object ignore return addIfNotIgnored(name, value, ignoreValue, Object::toString); } + /** + * Add the result of the given supplier. If the supplier return {@code null} or an exceptions + * is thrown, then nothing is added - the result is ignored. + */ + public ToStringBuilder addObjOpSafe(String name, Supplier body) { + return addObj(name, ObjectUtils.safeGetOrNull(body)); + } + /** * Use this if you would like a custom toString function to convert the value. If the given value * is null, then the value is not printed. *

* Implementation note! The "Op" (Operation) suffix is necessary to separate this from - * {@link #addObj(String, Object, Object)}, when the last argument is null. + * {@link #addObj(String, Object, Object)}, when the last argument is null. */ public ToStringBuilder addObjOp( String name, @@ -176,7 +186,7 @@ public ToStringBuilder addDoubles(String name, double[] value, double ignoreValu return addIt(name, Arrays.toString(value)); } - /** Add collection if not null or not empty, all elements are added */ + /** Add the collection if not null or not empty, all elements are added */ public ToStringBuilder addCol(String name, Collection c) { return addIfNotNull(name, c == null || c.isEmpty() ? null : c); } 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 3eb26150d97..642dbd2d6e5 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 @@ -107,7 +107,9 @@ public int getSecondsOffset() { public String toString() { return ToStringBuilder .of(TripScheduleWithOffset.class) - .addObj("trip", pattern.debugInfo()) + .addObj("info", pattern.debugInfo()) + .addObjOpSafe("id", () -> tripTimes.getTrip().getId()) + .addObjOpSafe("pattern.id", () -> pattern.getTripPattern().getPattern().getId()) .addServiceTime("depart", secondsOffset + getOriginalTripTimes().getDepartureTime(0)) .toString(); } diff --git a/src/main/java/org/opentripplanner/transit/model/network/RoutingTripPattern.java b/src/main/java/org/opentripplanner/transit/model/network/RoutingTripPattern.java index 00033b5f798..98d30432b32 100644 --- a/src/main/java/org/opentripplanner/transit/model/network/RoutingTripPattern.java +++ b/src/main/java/org/opentripplanner/transit/model/network/RoutingTripPattern.java @@ -117,7 +117,7 @@ public Route route() { @Override public String debugInfo() { - return pattern.logName() + " @" + index; + return pattern.logName() + " #" + index; } @Override diff --git a/src/test/java/org/opentripplanner/framework/lang/ObjectUtilsTest.java b/src/test/java/org/opentripplanner/framework/lang/ObjectUtilsTest.java index 9237b221fe5..274fb3e8700 100644 --- a/src/test/java/org/opentripplanner/framework/lang/ObjectUtilsTest.java +++ b/src/test/java/org/opentripplanner/framework/lang/ObjectUtilsTest.java @@ -4,6 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import java.time.Duration; import java.util.concurrent.atomic.AtomicReference; import org.junit.jupiter.api.Test; @@ -48,6 +49,18 @@ void requireNotInitialized() { assertEquals("Field is already set! Old value: old, new value: new.", ex.getMessage()); } + @Test + void safeGetOrNull() { + assertEquals("test", ObjectUtils.safeGetOrNull(() -> "test")); + assertEquals(3000, ObjectUtils.safeGetOrNull(() -> Duration.ofSeconds(3).toMillis())); + assertNull(ObjectUtils.safeGetOrNull(() -> null)); + assertNull( + ObjectUtils.safeGetOrNull(() -> { + throw new NullPointerException("Something went wrong - ignore"); + }) + ); + } + @Test void toStringTest() { assertEquals("1", ObjectUtils.toString(1)); diff --git a/src/test/java/org/opentripplanner/framework/tostring/ToStringBuilderTest.java b/src/test/java/org/opentripplanner/framework/tostring/ToStringBuilderTest.java index 3e87006e953..90254c321a1 100644 --- a/src/test/java/org/opentripplanner/framework/tostring/ToStringBuilderTest.java +++ b/src/test/java/org/opentripplanner/framework/tostring/ToStringBuilderTest.java @@ -111,6 +111,26 @@ public void addObj() { ); } + @Test + public void addObjOpSafe() { + assertEquals( + "ToStringBuilderTest{obj: Foo{a: 5, b: 'X'}}", + subject().addObjOpSafe("obj", () -> new Foo(5, "X")).toString() + ); + assertEquals("ToStringBuilderTest{}", subject().addObjOpSafe("obj", () -> null).toString()); + assertEquals( + "ToStringBuilderTest{}", + subject() + .addObjOpSafe( + "obj", + () -> { + throw new IllegalStateException("Ignore"); + } + ) + .toString() + ); + } + @Test public void addObjOp() { var duration = Duration.ofMinutes(1); From dd9ec7000f49332e6ff39ad867b48e69a6ed7589 Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Fri, 26 Jan 2024 19:16:49 +0000 Subject: [PATCH 61/69] Add changelog entry for #5637 [ci skip] --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index 7fc6a512c7a..28a5e9b8ee5 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -81,6 +81,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Remove `FareComponent` [#5613](https://github.com/opentripplanner/OpenTripPlanner/pull/5613) - Add AreaStop layer to new debug frontend [#5636](https://github.com/opentripplanner/OpenTripPlanner/pull/5636) - Allow configuration of vector tiles base path [#5627](https://github.com/opentripplanner/OpenTripPlanner/pull/5627) +- Change Transmodel API path to `/otp/transmodel/v3` [#5637](https://github.com/opentripplanner/OpenTripPlanner/pull/5637) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.4.0 (2023-09-13) From 4412c7fe3ab1ad36f5b5d27dafcaee6c47a0f6eb Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 26 Jan 2024 22:33:05 +0100 Subject: [PATCH 62/69] Update chat badge --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4486818745b..2f2e910862c 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) +[![Join the chat at https://gitter.im/opentripplanner/OpenTripPlanner](https://img.shields.io/matrix/opentripplanner%3Amatrix.org?label=Gitter%20chat&color=%2342ac8c +)](https://gitter.im/opentripplanner/OpenTripPlanner) [![codecov](https://codecov.io/gh/opentripplanner/OpenTripPlanner/branch/dev-2.x/graph/badge.svg?token=ak4PbIKgZ1)](https://codecov.io/gh/opentripplanner/OpenTripPlanner) [![Docker Pulls](https://img.shields.io/docker/pulls/opentripplanner/opentripplanner)](https://hub.docker.com/r/opentripplanner/opentripplanner) From 5e05d21ccb1e2f43069efe2929fcad45a823748d Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 26 Jan 2024 22:34:18 +0100 Subject: [PATCH 63/69] Revert "Update chat badge" This reverts commit 4412c7fe3ab1ad36f5b5d27dafcaee6c47a0f6eb. --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 2f2e910862c..4486818745b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ ## Overview -[![Join the chat at https://gitter.im/opentripplanner/OpenTripPlanner](https://img.shields.io/matrix/opentripplanner%3Amatrix.org?label=Gitter%20chat&color=%2342ac8c -)](https://gitter.im/opentripplanner/OpenTripPlanner) +[![Join the chat at https://gitter.im/opentripplanner/OpenTripPLanner](https://badges.gitter.im/opentripplanner/OpenTripPlanner.svg)](https://gitter.im/opentripplanner/OpenTripPlanner) [![codecov](https://codecov.io/gh/opentripplanner/OpenTripPlanner/branch/dev-2.x/graph/badge.svg?token=ak4PbIKgZ1)](https://codecov.io/gh/opentripplanner/OpenTripPlanner) [![Docker Pulls](https://img.shields.io/docker/pulls/opentripplanner/opentripplanner)](https://hub.docker.com/r/opentripplanner/opentripplanner) From 40c99421cf4f8336ffaaefb2f211fb9174423251 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sat, 27 Jan 2024 10:40:09 +0100 Subject: [PATCH 64/69] Update Github Actions --- .github/workflows/cibuild.yml | 28 +++++++++++++------------- .github/workflows/debug-client.yml | 2 +- .github/workflows/performance-test.yml | 4 ++-- .github/workflows/post-merge.yml | 4 ++-- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/cibuild.yml b/.github/workflows/cibuild.yml index c2979504992..28a84953af2 100644 --- a/.github/workflows/cibuild.yml +++ b/.github/workflows/cibuild.yml @@ -20,20 +20,20 @@ jobs: timeout-minutes: 20 steps: # Starting in v2.2 checkout action fetches all tags when fetch-depth=0, for auto-versioning. - - uses: actions/checkout@v3.3.0 + - uses: actions/checkout@v4 with: fetch-depth: 0 # nodejs is needed because the dynamic download of it via the prettier maven plugin often # times out # Example: https://github.com/opentripplanner/OpenTripPlanner/actions/runs/4490450225/jobs/7897533439 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: 18 # Java setup step completes very fast, no need to run in a preconfigured docker container - name: Set up JDK 21 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: 21 distribution: temurin @@ -65,9 +65,9 @@ jobs: timeout-minutes: 20 runs-on: windows-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up JDK 21 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: 21 distribution: temurin @@ -91,7 +91,7 @@ jobs: steps: - - uses: actions/checkout@v3.3.0 + - uses: actions/checkout@v4 # this is necessary so that the correct credentials are put into the git configuration # when we push to dev-2.x and push the HTML to the git repo if: github.event_name == 'push' && (github.ref == 'refs/heads/dev-2.x' || github.ref == 'refs/heads/master') @@ -101,7 +101,7 @@ jobs: # was modified last fetch-depth: 1000 - - uses: actions/checkout@v3.3.0 + - uses: actions/checkout@v4 # for a simple PR where we don't push, we don't need any credentials if: github.event_name == 'pull_request' @@ -113,7 +113,7 @@ jobs: if: github.event_name == 'pull_request' run: mkdocs build - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: 18 @@ -174,8 +174,8 @@ jobs: if: github.repository_owner == 'opentripplanner' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3.1.0 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: 16 - name: Run code generator @@ -184,7 +184,7 @@ jobs: yarn install yarn generate - name: Set up JDK 21 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: 21 distribution: temurin @@ -199,16 +199,16 @@ jobs: - build-windows - build-linux steps: - - uses: actions/checkout@v3.1.0 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up JDK 21 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: 21 distribution: temurin cache: maven - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: 18 - name: Build container image with Jib, push to Dockerhub diff --git a/.github/workflows/debug-client.yml b/.github/workflows/debug-client.yml index aed7943e63a..de92c121db7 100644 --- a/.github/workflows/debug-client.yml +++ b/.github/workflows/debug-client.yml @@ -30,7 +30,7 @@ jobs: - uses: actions/checkout@v4 if: github.event_name == 'pull_request' - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: 18 diff --git a/.github/workflows/performance-test.yml b/.github/workflows/performance-test.yml index a5274d9839f..1b8201a01ae 100644 --- a/.github/workflows/performance-test.yml +++ b/.github/workflows/performance-test.yml @@ -60,14 +60,14 @@ jobs: profile: extended steps: - - uses: actions/checkout@v3.1.0 + - uses: actions/checkout@v4 if: matrix.profile == 'core' || github.ref == 'refs/heads/dev-2.x' with: fetch-depth: 0 - name: Set up JDK if: matrix.profile == 'core' || github.ref == 'refs/heads/dev-2.x' - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: 21 distribution: temurin diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml index 1500a0f9d9e..a2f29f0d1b0 100644 --- a/.github/workflows/post-merge.yml +++ b/.github/workflows/post-merge.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3.1.0 + uses: actions/checkout@v4 with: token: ${{ secrets.CHANGELOG_TOKEN }} @@ -62,7 +62,7 @@ jobs: git config --global user.email 'serialization-version-bot@opentripplanner.org' - name: Checkout - uses: actions/checkout@v3.1.0 + uses: actions/checkout@v4 with: token: ${{ secrets.CHANGELOG_TOKEN }} From 4ecf8de9c7cb182832be747ac7fcdd1b8d9293b4 Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Mon, 29 Jan 2024 07:45:26 +0000 Subject: [PATCH 65/69] Add changelog entry for #5625 [ci skip] --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index 28a5e9b8ee5..40b91bf47a6 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -82,6 +82,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Add AreaStop layer to new debug frontend [#5636](https://github.com/opentripplanner/OpenTripPlanner/pull/5636) - Allow configuration of vector tiles base path [#5627](https://github.com/opentripplanner/OpenTripPlanner/pull/5627) - Change Transmodel API path to `/otp/transmodel/v3` [#5637](https://github.com/opentripplanner/OpenTripPlanner/pull/5637) +- Add flexibleArea to GroupStop Quays [#5625](https://github.com/opentripplanner/OpenTripPlanner/pull/5625) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.4.0 (2023-09-13) From 7d36193a16a97dbdca89ad24afe4a6736f659b49 Mon Sep 17 00:00:00 2001 From: OTP Serialization Version Bot Date: Mon, 29 Jan 2024 07:45:46 +0000 Subject: [PATCH 66/69] Bump serialization version id for #5625 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c4737cc592b..ce77a303d7d 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ - 139 + 140 30.1 2.50 From 773ed216c401a754e5ea57357bd1f2ce6cde232a Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 29 Jan 2024 12:59:18 +0100 Subject: [PATCH 67/69] Remove 'street corners' [ci skip] --- docs/apis/Apis.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/apis/Apis.md b/docs/apis/Apis.md index 48b530a57e1..dd9280a047f 100644 --- a/docs/apis/Apis.md +++ b/docs/apis/Apis.md @@ -18,7 +18,7 @@ entities on a vector map. The [Actuator API](../sandbox/ActuatorAPI.md) provides endpoints for checking the health status of the OTP instance and reading live application metrics. -The [Geocoder API](../sandbox/GeocoderAPI.md) allows you to geocode street corners and stop names. +The [Geocoder API](../sandbox/GeocoderAPI.md) allows you to geocode stop names. ## Legacy APIs (to be removed) @@ -26,4 +26,4 @@ The OTP REST API used to power many apps and frontends. For years it was the onl OTP programmatically. Over time it has been replaced by the GraphQL APIs and is scheduled to be disabled by default -and eventually removed completely. It's therefore not recommended to use it. \ No newline at end of file +and eventually removed completely. It's therefore not recommended to use it. From 9e7c9bfe9bd5f481255261e71654346935544efa Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 29 Jan 2024 13:26:46 +0100 Subject: [PATCH 68/69] Update docs, closes #5500 [ci skip] --- doc-templates/Configuration.md | 4 ++-- docs/Configuration.md | 4 ++-- docs/SandboxExtension.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc-templates/Configuration.md b/doc-templates/Configuration.md index eabd4895a1f..6344e270570 100644 --- a/doc-templates/Configuration.md +++ b/doc-templates/Configuration.md @@ -128,8 +128,8 @@ you can run the following bash command: - `head -c 29 Graph.obj ==> OpenTripPlannerGraph;0000007;` (file header) - `head -c 28 Graph.obj | tail -c 7 ==> 0000007` (version id) -The Maven _pom.xml_, the _META-INF/MANIFEST.MF_, the OTP command line(`--serVerId`), log start-up -messages and all OTP APIs can be used to get the OTP Serialization Version Id. +The Maven _pom.xml_, the _META-INF/MANIFEST.MF_, the OTP command line(`--serializationVersionId`), +log start-up messages and all OTP APIs can be used to get the OTP Serialization Version Id. ## Include file directive diff --git a/docs/Configuration.md b/docs/Configuration.md index d43ff150926..858edf0f9b4 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -155,8 +155,8 @@ you can run the following bash command: - `head -c 29 Graph.obj ==> OpenTripPlannerGraph;0000007;` (file header) - `head -c 28 Graph.obj | tail -c 7 ==> 0000007` (version id) -The Maven _pom.xml_, the _META-INF/MANIFEST.MF_, the OTP command line(`--serVerId`), log start-up -messages and all OTP APIs can be used to get the OTP Serialization Version Id. +The Maven _pom.xml_, the _META-INF/MANIFEST.MF_, the OTP command line(`--serializationVersionId`), +log start-up messages and all OTP APIs can be used to get the OTP Serialization Version Id. ## Include file directive diff --git a/docs/SandboxExtension.md b/docs/SandboxExtension.md index 38988f8245f..4b978313ca6 100644 --- a/docs/SandboxExtension.md +++ b/docs/SandboxExtension.md @@ -11,7 +11,7 @@ provided "as is". - [Google Cloud Storage](sandbox/GoogleCloudStorage.md) - Enable Google Cloud Storage as a OTP Data Source - [Actuator API](sandbox/ActuatorAPI.md) - API used to check the health status of the OTP instance. -- [Geocoder API](sandbox/GeocoderAPI.md) - Adds an API to search for corners, stops and stations. +- [Geocoder API](sandbox/GeocoderAPI.md) - Adds an API to search for stops and stations. - [Transfer analyser](sandbox/transferanalyzer.md) - Module used for analyzing the transfers between nearby stops generated by routing via OSM data. - [SIRI Updater](sandbox/SiriUpdater.md) - Update OTP with real-time information from a Transmodel SIRI data source. From 698076700bc9d54e615892e6c94f7104510b675d Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Tue, 30 Jan 2024 10:01:00 +0000 Subject: [PATCH 69/69] Add changelog entry for #5638 [ci skip] --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index 40b91bf47a6..35fc86ec3bc 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -83,6 +83,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Allow configuration of vector tiles base path [#5627](https://github.com/opentripplanner/OpenTripPlanner/pull/5627) - Change Transmodel API path to `/otp/transmodel/v3` [#5637](https://github.com/opentripplanner/OpenTripPlanner/pull/5637) - Add flexibleArea to GroupStop Quays [#5625](https://github.com/opentripplanner/OpenTripPlanner/pull/5625) +- Pass-through should override transit-group-priority [#5638](https://github.com/opentripplanner/OpenTripPlanner/pull/5638) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.4.0 (2023-09-13)