From c58f2156e6a12c29b98e214a3f06411dabd43c8e Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Fri, 16 Aug 2024 22:27:34 +0200 Subject: [PATCH 01/51] ENH: NAV-131 - Add more information requirements to ScheduleInformationService interface. --- .../service/PublicTransitSpringService.java | 15 +++++++++++++ .../service/ScheduleInformationService.java | 21 +++++++++++++++++++ .../gtfs/raptor/GtfsRaptorService.java | 16 ++++++++++++++ .../naviqore/app/controller/DummyService.java | 15 +++++++++++++ 4 files changed, 67 insertions(+) diff --git a/src/main/java/ch/naviqore/app/service/PublicTransitSpringService.java b/src/main/java/ch/naviqore/app/service/PublicTransitSpringService.java index 170f4446..46ad68c1 100644 --- a/src/main/java/ch/naviqore/app/service/PublicTransitSpringService.java +++ b/src/main/java/ch/naviqore/app/service/PublicTransitSpringService.java @@ -56,6 +56,21 @@ public Validity getValidity() { return delegate.getValidity(); } + @Override + public boolean hasAccessibilityInformation() { + return delegate.hasAccessibilityInformation(); + } + + @Override + public boolean hasBikeInformation() { + return delegate.hasBikeInformation(); + } + + @Override + public boolean hasTravelModeInformation() { + return delegate.hasTravelModeInformation(); + } + @Override public List getStops(String like, SearchType searchType) { return delegate.getStops(like, searchType); diff --git a/src/main/java/ch/naviqore/service/ScheduleInformationService.java b/src/main/java/ch/naviqore/service/ScheduleInformationService.java index b57e77eb..af4973f3 100644 --- a/src/main/java/ch/naviqore/service/ScheduleInformationService.java +++ b/src/main/java/ch/naviqore/service/ScheduleInformationService.java @@ -21,6 +21,27 @@ public interface ScheduleInformationService { */ Validity getValidity(); + /** + * Checks if the schedule has accessibility information. + * + * @return true if the schedule has accessibility information, false otherwise + */ + boolean hasAccessibilityInformation(); + + /** + * Checks if the schedule has bike information. + * + * @return true if the schedule has bike information, false otherwise + */ + boolean hasBikeInformation(); + + /** + * Checks if the schedule has travel mode information. + * + * @return true if the schedule has travel mode information, false otherwise + */ + boolean hasTravelModeInformation(); + /** * Searches for stops by name. * diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java b/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java index 72d395d5..82b83373 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java @@ -59,6 +59,22 @@ public class GtfsRaptorService implements PublicTransitService { raptorAlgorithm = new GtfsToRaptorConverter(schedule, additionalTransfers, raptorConfig).convert(); } + @Override + public boolean hasAccessibilityInformation() { + return schedule.hasStopAccessibilityInformation(); + } + + @Override + public boolean hasBikeInformation() { + return schedule.hasTripBikeInformation(); + } + + @Override + public boolean hasTravelModeInformation() { + // GTFS requires routes to have a mode, so this is always true + return true; + } + @Override public List getStops(String like, SearchType searchType) { return stopSearchIndex.search(like.toLowerCase(), TypeMapper.map(searchType)) diff --git a/src/test/java/ch/naviqore/app/controller/DummyService.java b/src/test/java/ch/naviqore/app/controller/DummyService.java index e969cee2..8d72ba2a 100644 --- a/src/test/java/ch/naviqore/app/controller/DummyService.java +++ b/src/test/java/ch/naviqore/app/controller/DummyService.java @@ -64,6 +64,21 @@ public boolean isWithin(LocalDate date) { }; } + @Override + public boolean hasAccessibilityInformation() { + return false; + } + + @Override + public boolean hasBikeInformation() { + return false; + } + + @Override + public boolean hasTravelModeInformation() { + return false; + } + @Override public List getConnections(GeoCoordinate source, GeoCoordinate target, LocalDateTime time, TimeType timeType, ConnectionQueryConfig config) { From 74c6a1bea773f89dba6ac29ec545becf27dcc6f1 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Fri, 16 Aug 2024 23:20:02 +0200 Subject: [PATCH 02/51] REFACTOR: NAV-131 - Remove the time type dto enum and use service enum to reduce code duplication. --- .../ch/naviqore/app/controller/RoutingController.java | 2 +- src/main/java/ch/naviqore/app/dto/DtoMapper.java | 10 +--------- src/main/java/ch/naviqore/app/dto/StopConnection.java | 1 + src/main/java/ch/naviqore/app/dto/TimeType.java | 6 ------ .../naviqore/app/controller/RoutingControllerTest.java | 1 + 5 files changed, 4 insertions(+), 16 deletions(-) delete mode 100644 src/main/java/ch/naviqore/app/dto/TimeType.java diff --git a/src/main/java/ch/naviqore/app/controller/RoutingController.java b/src/main/java/ch/naviqore/app/controller/RoutingController.java index 65b1af6b..d16b13ff 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingController.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingController.java @@ -2,7 +2,7 @@ import ch.naviqore.app.dto.Connection; import ch.naviqore.app.dto.StopConnection; -import ch.naviqore.app.dto.TimeType; +import ch.naviqore.service.TimeType; import ch.naviqore.service.PublicTransitService; import ch.naviqore.service.ScheduleInformationService; import ch.naviqore.service.Stop; diff --git a/src/main/java/ch/naviqore/app/dto/DtoMapper.java b/src/main/java/ch/naviqore/app/dto/DtoMapper.java index b6a5ff53..577e0e9c 100644 --- a/src/main/java/ch/naviqore/app/dto/DtoMapper.java +++ b/src/main/java/ch/naviqore/app/dto/DtoMapper.java @@ -1,7 +1,6 @@ package ch.naviqore.app.dto; import ch.naviqore.service.SearchType; -import ch.naviqore.service.TimeType; import ch.naviqore.service.*; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -50,13 +49,6 @@ public static SearchType map(ch.naviqore.app.dto.SearchType searchType) { }; } - public static TimeType map(ch.naviqore.app.dto.TimeType timeType) { - return switch (timeType) { - case DEPARTURE -> TimeType.DEPARTURE; - case ARRIVAL -> TimeType.ARRIVAL; - }; - } - public static Connection map(ch.naviqore.service.Connection connection) { List legs = connection.getLegs().stream().map(leg -> leg.accept(new LegVisitorImpl())).toList(); return new Connection(legs); @@ -67,7 +59,7 @@ public static List map(List connecti } public static List map(Map connections, - ch.naviqore.app.dto.TimeType timeType, boolean returnConnections) { + TimeType timeType, boolean returnConnections) { List arrivals = new ArrayList<>(); for (Map.Entry entry : connections.entrySet()) { arrivals.add(new StopConnection(entry.getKey(), entry.getValue(), timeType, returnConnections)); diff --git a/src/main/java/ch/naviqore/app/dto/StopConnection.java b/src/main/java/ch/naviqore/app/dto/StopConnection.java index 6ee81b59..247e1bc6 100644 --- a/src/main/java/ch/naviqore/app/dto/StopConnection.java +++ b/src/main/java/ch/naviqore/app/dto/StopConnection.java @@ -1,5 +1,6 @@ package ch.naviqore.app.dto; +import ch.naviqore.service.TimeType; import lombok.*; import java.time.LocalDateTime; diff --git a/src/main/java/ch/naviqore/app/dto/TimeType.java b/src/main/java/ch/naviqore/app/dto/TimeType.java deleted file mode 100644 index 77926818..00000000 --- a/src/main/java/ch/naviqore/app/dto/TimeType.java +++ /dev/null @@ -1,6 +0,0 @@ -package ch.naviqore.app.dto; - -public enum TimeType { - DEPARTURE, - ARRIVAL -} diff --git a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java index d83d9a77..339c5649 100644 --- a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java +++ b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java @@ -1,6 +1,7 @@ package ch.naviqore.app.controller; import ch.naviqore.app.dto.*; +import ch.naviqore.service.TimeType; import ch.naviqore.utils.spatial.GeoCoordinate; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; From e228bb0d8564a2984a2930563a9a699145584b43 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Fri, 16 Aug 2024 23:38:59 +0200 Subject: [PATCH 03/51] ENH: NAV-131 - Add TravelMode Enum. --- src/main/java/ch/naviqore/service/TravelMode.java | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/main/java/ch/naviqore/service/TravelMode.java diff --git a/src/main/java/ch/naviqore/service/TravelMode.java b/src/main/java/ch/naviqore/service/TravelMode.java new file mode 100644 index 00000000..e29ede1b --- /dev/null +++ b/src/main/java/ch/naviqore/service/TravelMode.java @@ -0,0 +1,11 @@ +package ch.naviqore.service; + +public enum TravelMode { + BUS, + TRAM, + RAIL, + SHIP, + SUBWAY, + AERIAL_LIFT, + FUNICULAR, +} From 445c59d199a952081678fc65566b51106c409513 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Fri, 16 Aug 2024 23:55:54 +0200 Subject: [PATCH 04/51] ENH: NAV-131 - Extend ConnectionQueryConfig with more query options. --- .../ch/naviqore/service/config/ConnectionQueryConfig.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/ch/naviqore/service/config/ConnectionQueryConfig.java b/src/main/java/ch/naviqore/service/config/ConnectionQueryConfig.java index 59f038eb..caa4647d 100644 --- a/src/main/java/ch/naviqore/service/config/ConnectionQueryConfig.java +++ b/src/main/java/ch/naviqore/service/config/ConnectionQueryConfig.java @@ -1,9 +1,12 @@ package ch.naviqore.service.config; +import ch.naviqore.service.TravelMode; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.ToString; +import java.util.EnumSet; + @RequiredArgsConstructor @Getter @ToString @@ -13,5 +16,8 @@ public class ConnectionQueryConfig { private final int minimumTransferDuration; private final int maximumTransferNumber; private final int maximumTravelTime; + private final boolean wheelchairAccessible; + private final boolean bikeAllowed; + private final EnumSet travelModes; } From e00cf6e271a043cb26adc11ebda1f8382a99dc03 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Fri, 16 Aug 2024 23:59:57 +0200 Subject: [PATCH 05/51] ENH: NAV-131 - Include extended query options to routing controller. --- .../app/controller/RoutingController.java | 46 +++++++++++-------- .../controller/RoutingRequestValidator.java | 23 +++++++++- 2 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/main/java/ch/naviqore/app/controller/RoutingController.java b/src/main/java/ch/naviqore/app/controller/RoutingController.java index d16b13ff..6b5fdd08 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingController.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingController.java @@ -2,10 +2,7 @@ import ch.naviqore.app.dto.Connection; import ch.naviqore.app.dto.StopConnection; -import ch.naviqore.service.TimeType; -import ch.naviqore.service.PublicTransitService; -import ch.naviqore.service.ScheduleInformationService; -import ch.naviqore.service.Stop; +import ch.naviqore.service.*; import ch.naviqore.service.config.ConnectionQueryConfig; import ch.naviqore.service.exception.ConnectionRoutingException; import ch.naviqore.utils.spatial.GeoCoordinate; @@ -25,6 +22,7 @@ import org.springframework.web.server.ResponseStatusException; import java.time.LocalDateTime; +import java.util.EnumSet; import java.util.List; import static ch.naviqore.app.dto.DtoMapper.map; @@ -63,8 +61,10 @@ public List getConnections(@RequestParam(required = false) String so @RequestParam(required = false) Integer maxWalkingDuration, @RequestParam(required = false) Integer maxTransferNumber, @RequestParam(required = false) Integer maxTravelTime, - @RequestParam(required = false, defaultValue = "0") int minTransferTime) { - + @RequestParam(required = false, defaultValue = "0") int minTransferTime, + @RequestParam(required = false, defaultValue = "false") boolean wheelchairAccessible, + @RequestParam(required = false, defaultValue = "false") boolean bikeAllowed, + @RequestParam(required = false) EnumSet travelModes) { // get coordinates if available GeoCoordinate sourceCoordinate = Utils.getCoordinateIfAvailable(sourceStopId, sourceLatitude, sourceLongitude, GlobalValidator.StopType.SOURCE); @@ -78,19 +78,19 @@ public List getConnections(@RequestParam(required = false) String so // configure routing request dateTime = GlobalValidator.validateAndSetDefaultDateTime(dateTime, service); ConnectionQueryConfig config = Utils.createConfig(maxWalkingDuration, maxTransferNumber, maxTravelTime, - minTransferTime); + minTransferTime, wheelchairAccessible, bikeAllowed, travelModes, service); // determine routing case and get connections try { if (sourceStop != null && targetStop != null) { RoutingRequestValidator.validateStops(sourceStopId, targetStopId); - return map(service.getConnections(sourceStop, targetStop, dateTime, map(timeType), config)); + return map(service.getConnections(sourceStop, targetStop, dateTime, timeType, config)); } else if (sourceStop != null) { - return map(service.getConnections(sourceStop, targetCoordinate, dateTime, map(timeType), config)); + return map(service.getConnections(sourceStop, targetCoordinate, dateTime, timeType, config)); } else if (targetStop != null) { - return map(service.getConnections(sourceCoordinate, targetStop, dateTime, map(timeType), config)); + return map(service.getConnections(sourceCoordinate, targetStop, dateTime, timeType, config)); } else { - return map(service.getConnections(sourceCoordinate, targetCoordinate, dateTime, map(timeType), config)); + return map(service.getConnections(sourceCoordinate, targetCoordinate, dateTime, timeType, config)); } } catch (ConnectionRoutingException e) { handleConnectionRoutingException(e); @@ -112,6 +112,9 @@ public List getIsolines(@RequestParam(required = false) String s @RequestParam(required = false) Integer maxTransferNumber, @RequestParam(required = false) Integer maxTravelTime, @RequestParam(required = false, defaultValue = "0") int minTransferTime, + @RequestParam(required = false, defaultValue = "false") boolean wheelchairAccessible, + @RequestParam(required = false, defaultValue = "false") boolean bikeAllowed, + @RequestParam(required = false) EnumSet travelModes, @RequestParam(required = false, defaultValue = "false") boolean returnConnections) { // get stops or coordinates if available @@ -122,15 +125,14 @@ public List getIsolines(@RequestParam(required = false) String s // configure routing request dateTime = GlobalValidator.validateAndSetDefaultDateTime(dateTime, service); ConnectionQueryConfig config = Utils.createConfig(maxWalkingDuration, maxTransferNumber, maxTravelTime, - minTransferTime); + minTransferTime, wheelchairAccessible, bikeAllowed, travelModes, service); // determine routing case and get isolines try { if (sourceStop != null) { - return map(service.getIsoLines(sourceStop, dateTime, map(timeType), config), timeType, - returnConnections); + return map(service.getIsoLines(sourceStop, dateTime, timeType, config), timeType, returnConnections); } else { - return map(service.getIsoLines(sourceCoordinate, dateTime, map(timeType), config), timeType, + return map(service.getIsoLines(sourceCoordinate, dateTime, timeType, config), timeType, returnConnections); } } catch (ConnectionRoutingException e) { @@ -156,17 +158,25 @@ private static class Utils { private static ConnectionQueryConfig createConfig(@Nullable Integer maxWalkingDuration, @Nullable Integer maxTransferNumber, - @Nullable Integer maxTravelTime, int minTransferTime) { + @Nullable Integer maxTravelTime, int minTransferTime, + boolean wheelchairAccessible, boolean bikeAllowed, + @Nullable EnumSet travelModes, + PublicTransitService service) { // replace null values with integer max value maxWalkingDuration = setToMaxIfNull(maxWalkingDuration); maxTransferNumber = setToMaxIfNull(maxTransferNumber); maxTravelTime = setToMaxIfNull(maxTravelTime); + if (travelModes == null || travelModes.isEmpty()) { + travelModes = EnumSet.allOf(TravelMode.class); + } + // validate and create config RoutingRequestValidator.validateQueryParams(maxWalkingDuration, maxTransferNumber, maxTravelTime, - minTransferTime); - return new ConnectionQueryConfig(maxWalkingDuration, minTransferTime, maxTransferNumber, maxTravelTime); + minTransferTime, wheelchairAccessible, bikeAllowed, travelModes, service); + return new ConnectionQueryConfig(maxWalkingDuration, minTransferTime, maxTransferNumber, maxTravelTime, + wheelchairAccessible, bikeAllowed, travelModes); } private static int setToMaxIfNull(Integer value) { diff --git a/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java b/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java index 366116d8..adda7883 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java @@ -1,5 +1,7 @@ package ch.naviqore.app.controller; +import ch.naviqore.service.PublicTransitService; +import ch.naviqore.service.TravelMode; import ch.naviqore.utils.spatial.GeoCoordinate; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -7,6 +9,8 @@ import org.springframework.http.HttpStatus; import org.springframework.web.server.ResponseStatusException; +import java.util.EnumSet; + @NoArgsConstructor(access = AccessLevel.NONE) final class RoutingRequestValidator { @@ -20,7 +24,8 @@ public static GeoCoordinate validateCoordinate(double latitude, double longitude } public static void validateQueryParams(int maxWalkingDuration, int maxTransferNumber, int maxTravelTime, - int minTransferTime) { + int minTransferTime, boolean wheelchairAccessible, boolean bikeAllowed, + EnumSet travelModes, PublicTransitService service) { if (maxWalkingDuration < 0) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Max walking duration must be greater than or equal to 0."); @@ -36,6 +41,22 @@ public static void validateQueryParams(int maxWalkingDuration, int maxTransferNu throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Min transfer time must be greater than or equal to 0."); } + + // If the service does not support accessibility information, bike information, or travel mode information, + // only default values are allowed (i.e., false for wheelchairAccessible, false for bikeAllowed, + // and all travel modes). + if (wheelchairAccessible && !service.hasAccessibilityInformation()) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, + "Accessibility information is not available for this service."); + } + if (bikeAllowed && !service.hasBikeInformation()) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, + "Bike information is not available for this service."); + } + if (!travelModes.containsAll(EnumSet.allOf(TravelMode.class)) && !service.hasTravelModeInformation()) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, + "Service does not support travel mode information."); + } } public static void validateStopParameters(@Nullable String stopId, @Nullable Double latitude, From 55f22b3eca2c01253868703d3f73f8ce9e640c03 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Sat, 17 Aug 2024 00:41:50 +0200 Subject: [PATCH 06/51] TEST: NAV-131 - Refactor routing controller test to use more parametrized tests. --- .../naviqore/app/controller/DummyService.java | 12 +- .../app/controller/RoutingControllerTest.java | 249 ++++++++++-------- .../gtfs/raptor/GtfsRaptorServiceIT.java | 2 +- 3 files changed, 146 insertions(+), 117 deletions(-) diff --git a/src/test/java/ch/naviqore/app/controller/DummyService.java b/src/test/java/ch/naviqore/app/controller/DummyService.java index 8d72ba2a..4525251c 100644 --- a/src/test/java/ch/naviqore/app/controller/DummyService.java +++ b/src/test/java/ch/naviqore/app/controller/DummyService.java @@ -8,15 +8,21 @@ import ch.naviqore.service.exception.TripNotFoundException; import ch.naviqore.utils.spatial.GeoCoordinate; import lombok.NoArgsConstructor; +import lombok.Setter; import org.jetbrains.annotations.Nullable; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.*; +@Setter @NoArgsConstructor class DummyService implements PublicTransitService { + private boolean hasAccessibilityInformation; + private boolean hasBikeInformation; + private boolean hasTravelModeInformation; + static final DummyServiceModels.Stop STOP_A = new DummyServiceModels.Stop("A", "Stop A", new GeoCoordinate(0, 0)); static final DummyServiceModels.Stop STOP_B = new DummyServiceModels.Stop("B", "Stop B", new GeoCoordinate(1, 1)); static final DummyServiceModels.Stop STOP_C = new DummyServiceModels.Stop("C", "Stop C", new GeoCoordinate(2, 2)); @@ -66,17 +72,17 @@ public boolean isWithin(LocalDate date) { @Override public boolean hasAccessibilityInformation() { - return false; + return hasAccessibilityInformation; } @Override public boolean hasBikeInformation() { - return false; + return hasBikeInformation; } @Override public boolean hasTravelModeInformation() { - return false; + return hasTravelModeInformation; } @Override diff --git a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java index 339c5649..7ee88ef4 100644 --- a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java +++ b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java @@ -2,14 +2,20 @@ import ch.naviqore.app.dto.*; import ch.naviqore.service.TimeType; +import ch.naviqore.service.TravelMode; import ch.naviqore.utils.spatial.GeoCoordinate; import org.junit.jupiter.api.Nested; 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.springframework.http.HttpStatusCode; import org.springframework.web.server.ResponseStatusException; import java.time.LocalDateTime; +import java.util.EnumSet; import java.util.List; +import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.*; @@ -19,9 +25,63 @@ public class RoutingControllerTest { private final RoutingController routingController = new RoutingController(dummyService); + static Stream provideQueryConfigTestCombinations() { + int validMaxWalkingDuration = 30; + int validMaxTransferDuration = 2; + int validMaxTravelTime = 120; + int validMinTransferTime = 5; + boolean validWheelChairAccessible = false; + boolean validBikeAllowed = false; + EnumSet validTravelModes = EnumSet.allOf(TravelMode.class); + + return Stream.of( + Arguments.of("validValues", validMaxWalkingDuration, validMaxTransferDuration, validMaxTravelTime, + validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, true, true, + true, null), + Arguments.of("maxWalkingDurationEqualsNull", null, validMaxTransferDuration, validMaxTravelTime, + validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, true, true, + true, null), + Arguments.of("invalidMaxWalkingDuration", -1, validMaxTransferDuration, validMaxTravelTime, + validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, true, true, + true, "Max walking duration must be greater than or equal to 0."), + Arguments.of("maxTransferDurationEqualsNull", validMaxWalkingDuration, null, validMaxTravelTime, + validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, true, true, + true, null), + Arguments.of("invalidMaxTransferDuration", validMaxWalkingDuration, -1, validMaxTravelTime, + validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, true, true, + true, "Max transfer number must be greater than or equal to 0."), + Arguments.of("maxTravelTimeEqualsNull", validMaxWalkingDuration, validMaxTransferDuration, null, + validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, true, true, + true, null), + Arguments.of("invalidMaxTravelTime", validMaxWalkingDuration, validMaxTransferDuration, -1, + validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, true, true, + true, "Max travel time must be greater than 0."), + Arguments.of("invalidMinTransferTime", validMaxWalkingDuration, validMaxTransferDuration, + validMaxTravelTime, -1, validWheelChairAccessible, validBikeAllowed, validTravelModes, true, + true, true, "Min transfer time must be greater than or equal to 0.")); + } + + List getConnections(String sourceStopId, Double sourceLatitude, Double sourceLongitude, + String targetStopId, Double targetLatitude, Double targetLongitude, + LocalDateTime departureDateTime) { + return routingController.getConnections(sourceStopId, sourceLatitude, sourceLongitude, targetStopId, + targetLatitude, targetLongitude, departureDateTime, TimeType.DEPARTURE, null, null, null, 0, false, + false, null); + } + + List getIsolines(String sourceStopId, Double sourceLatitude, Double sourceLongitude, + LocalDateTime departureDateTime, TimeType timeType, boolean returnConnections) { + return routingController.getIsolines(sourceStopId, sourceLatitude, sourceLongitude, departureDateTime, timeType, + null, null, null, 0, false, false, null, returnConnections); + } + @Nested class Connections { + static Stream provideQueryConfigTestCombinations() { + return RoutingControllerTest.provideQueryConfigTestCombinations(); + } + @Test void testWithValidSourceAndTargetStopIds() { // Arrange @@ -30,8 +90,8 @@ void testWithValidSourceAndTargetStopIds() { LocalDateTime departureDateTime = LocalDateTime.now(); // Act - List connections = routingController.getConnections(sourceStopId, null, null, targetStopId, - null, null, departureDateTime, TimeType.DEPARTURE, 30, 2, 120, 5); + List connections = getConnections(sourceStopId, null, null, targetStopId, null, null, + departureDateTime); // Assert assertNotNull(connections); @@ -46,8 +106,8 @@ void testWithoutSourceStopIdButWithCoordinates() { LocalDateTime departureDateTime = LocalDateTime.now(); // Act - List connections = routingController.getConnections(null, sourceLatitude, sourceLongitude, - targetStopId, null, null, departureDateTime, TimeType.DEPARTURE, 30, 2, 120, 5); + List connections = getConnections(null, sourceLatitude, sourceLongitude, targetStopId, null, + null, departureDateTime); // Assert assertNotNull(connections); @@ -61,8 +121,7 @@ void testInvalidStopId() { // Act & Assert ResponseStatusException exception = assertThrows(ResponseStatusException.class, - () -> routingController.getConnections(invalidStopId, null, null, targetStopId, null, null, - LocalDateTime.now(), TimeType.DEPARTURE, 30, 2, 120, 5)); + () -> getConnections(invalidStopId, null, null, targetStopId, null, null, LocalDateTime.now())); assertEquals("The requested source stop with ID 'invalidStopId' was not found.", exception.getReason()); assertEquals(HttpStatusCode.valueOf(404), exception.getStatusCode()); } @@ -75,8 +134,7 @@ void testRoutingBetweenSameStops() { LocalDateTime departureDateTime = LocalDateTime.now(); // Act & Assert ResponseStatusException exception = assertThrows(ResponseStatusException.class, - () -> routingController.getConnections(sourceStopId, null, null, targetStopId, null, null, - departureDateTime, TimeType.DEPARTURE, 30, 2, 120, 5)); + () -> getConnections(sourceStopId, null, null, targetStopId, null, null, departureDateTime)); assertEquals( "The source stop ID and target stop ID cannot be the same. Please provide different stop IDs for the source and target.", exception.getReason()); @@ -87,8 +145,7 @@ void testRoutingBetweenSameStops() { void testMissingSourceStopAndSourceCoordinates() { // Act & Assert ResponseStatusException exception = assertThrows(ResponseStatusException.class, - () -> routingController.getConnections(null, null, null, "targetStopId", null, null, - LocalDateTime.now(), TimeType.DEPARTURE, 30, 2, 120, 5)); + () -> getConnections(null, null, null, "targetStopId", null, null, LocalDateTime.now())); assertEquals("Either sourceStopId or sourceLatitude and sourceLongitude must be provided.", exception.getReason()); assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); @@ -98,8 +155,7 @@ void testMissingSourceStopAndSourceCoordinates() { void testMissingTargetStopAndTargetCoordinates() { // Act & Assert ResponseStatusException exception = assertThrows(ResponseStatusException.class, - () -> routingController.getConnections("sourceStopId", null, null, null, null, null, - LocalDateTime.now(), TimeType.DEPARTURE, 30, 2, 120, 5)); + () -> getConnections("sourceStopId", null, null, null, null, null, LocalDateTime.now())); assertEquals("Either targetStopId or targetLatitude and targetLongitude must be provided.", exception.getReason()); assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); @@ -109,8 +165,7 @@ void testMissingTargetStopAndTargetCoordinates() { void testGivenSourceStopAndSourceCoordinates() { // Act & Assert ResponseStatusException exception = assertThrows(ResponseStatusException.class, - () -> routingController.getConnections("sourceStopId", 0., 0., "targetStopId", null, null, - LocalDateTime.now(), TimeType.DEPARTURE, 30, 2, 120, 5)); + () -> getConnections("sourceStopId", 0., 0., "targetStopId", null, null, LocalDateTime.now())); assertEquals("Only sourceStopId or sourceLatitude and sourceLongitude must be provided, but not both.", exception.getReason()); assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); @@ -120,8 +175,7 @@ void testGivenSourceStopAndSourceCoordinates() { void testGivenTargetStopAndTargetCoordinates() { // Act & Assert ResponseStatusException exception = assertThrows(ResponseStatusException.class, - () -> routingController.getConnections("sourceStopId", null, null, "targetStopId", 0., 0., - LocalDateTime.now(), TimeType.DEPARTURE, 30, 2, 120, 5)); + () -> getConnections("sourceStopId", null, null, "targetStopId", 0., 0., LocalDateTime.now())); assertEquals("Only targetStopId or targetLatitude and targetLongitude must be provided, but not both.", exception.getReason()); assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); @@ -131,57 +185,46 @@ void testGivenTargetStopAndTargetCoordinates() { void testInvalidCoordinates() { // Act & Assert ResponseStatusException exception = assertThrows(ResponseStatusException.class, - () -> routingController.getConnections(null, 91., 181., null, 32., 32., LocalDateTime.now(), - TimeType.DEPARTURE, 30, 2, 120, 5)); + () -> getConnections(null, 91., 181., null, 32., 32., LocalDateTime.now())); assertEquals("Coordinates must be valid, Latitude between -90 and 90 and Longitude between -180 and 180.", exception.getReason()); assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); } - @Test - void testInvalidMaxTransferNumber() { - // Act & Assert - ResponseStatusException exception = assertThrows(ResponseStatusException.class, - () -> routingController.getConnections(null, 0., 0., null, 0., 0., LocalDateTime.now(), - TimeType.DEPARTURE, 30, -2, 120, 5)); - assertEquals("Max transfer number must be greater than or equal to 0.", exception.getReason()); - assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); - } - - @Test - void testInvalidMaxWalkingDuration() { - // Act & Assert - ResponseStatusException exception = assertThrows(ResponseStatusException.class, - () -> routingController.getConnections(null, 0., 0., null, 0., 0., LocalDateTime.now(), - TimeType.DEPARTURE, -30, 2, 120, 5)); - assertEquals("Max walking duration must be greater than or equal to 0.", exception.getReason()); - assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); - } - - @Test - void testInvalidMaxTravelTime() { - // Act & Assert - ResponseStatusException exception = assertThrows(ResponseStatusException.class, - () -> routingController.getConnections(null, 0., 0., null, 0., 0., LocalDateTime.now(), - TimeType.DEPARTURE, 30, 2, -120, 5)); - assertEquals("Max travel time must be greater than 0.", exception.getReason()); - assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); - } - - @Test - void testInvalidMinTransferTime() { - // Act & Assert - ResponseStatusException exception = assertThrows(ResponseStatusException.class, - () -> routingController.getConnections(null, 0., 0., null, 0., 0., LocalDateTime.now(), - TimeType.DEPARTURE, 30, 2, 120, -5)); - assertEquals("Min transfer time must be greater than or equal to 0.", exception.getReason()); - assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + @ParameterizedTest(name = "connectionQueryConfig_{0}") + @MethodSource("provideQueryConfigTestCombinations") + void testQueryConfigValues(String name, Integer maxWalkingDuration, Integer maxTransferDuration, + Integer maxTravelTime, int minTransferTime, boolean wheelChairAccessible, + boolean bikeAllowed, EnumSet travelModes, + boolean hasAccessibilityInformation, boolean hasBikeInformation, + boolean hasTravelModeInformation, String errorMessage) { + + dummyService.setHasAccessibilityInformation(hasAccessibilityInformation); + dummyService.setHasBikeInformation(hasBikeInformation); + dummyService.setHasTravelModeInformation(hasTravelModeInformation); + + if (errorMessage == null) { + routingController.getConnections(null, 0., 0., null, 0., 0., LocalDateTime.now(), TimeType.DEPARTURE, + maxWalkingDuration, maxTransferDuration, maxTravelTime, minTransferTime, wheelChairAccessible, + bikeAllowed, travelModes); + } else { + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> routingController.getConnections(null, 0., 0., null, 0., 0., LocalDateTime.now(), + TimeType.DEPARTURE, maxWalkingDuration, maxTransferDuration, maxTravelTime, + minTransferTime, wheelChairAccessible, bikeAllowed, travelModes)); + assertEquals(errorMessage, exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } } } @Nested class Isolines { + static Stream provideQueryConfigTestCombinations() { + return RoutingControllerTest.provideQueryConfigTestCombinations(); + } + @Test void testFromStopReturnConnectionsFalse() { // Arrange @@ -190,7 +233,7 @@ void testFromStopReturnConnectionsFalse() { // Act List stopConnections = routingController.getIsolines(sourceStopId, null, null, time, - TimeType.DEPARTURE, 30, 2, 120, 5, false); + TimeType.DEPARTURE, 30, 2, 120, 5, false, false, null, false); assertNotNull(stopConnections); @@ -213,7 +256,7 @@ void testFromStopReturnConnectionsTrue() { LocalDateTime expectedStartTime = LocalDateTime.now(); List stopConnections = routingController.getIsolines(sourceStopId, null, null, null, - TimeType.DEPARTURE, 30, 2, 120, 5, true); + TimeType.DEPARTURE, 30, 2, 120, 5, false, false, null, true); assertNotNull(stopConnections); @@ -256,8 +299,8 @@ void testFromCoordinatesReturnConnectionsFalse() { LocalDateTime time = LocalDateTime.now(); // Act - List stopConnections = routingController.getIsolines(null, sourceLatitude, sourceLongitude, - time, TimeType.DEPARTURE, 30, 2, 120, 5, false); + List stopConnections = getIsolines(null, sourceLatitude, sourceLongitude, time, + TimeType.DEPARTURE, false); assertNotNull(stopConnections); @@ -279,8 +322,8 @@ void testFromCoordinateReturnConnectionsTrue() { // This tests if the time is set to now if null LocalDateTime expectedStartTime = LocalDateTime.now(); - List stopConnections = routingController.getIsolines(null, sourceCoordinate.latitude(), - sourceCoordinate.longitude(), null, TimeType.DEPARTURE, 30, 2, 120, 5, true); + List stopConnections = getIsolines(null, sourceCoordinate.latitude(), + sourceCoordinate.longitude(), null, TimeType.DEPARTURE, true); assertNotNull(stopConnections); @@ -321,8 +364,7 @@ void testFromStopReturnConnectionsTrueTimeTypeArrival() { // Arrange String sourceStopId = "G"; - List stopConnections = routingController.getIsolines(sourceStopId, null, null, null, - TimeType.ARRIVAL, 30, 2, 120, 5, true); + List stopConnections = getIsolines(sourceStopId, null, null, null, TimeType.ARRIVAL, true); // This tests if the time is set to now if null LocalDateTime expectedArrivalTime = LocalDateTime.now(); @@ -367,8 +409,8 @@ void testFromCoordinateReturnConnectionsTrueTimeTypeArrival() { // Arrange GeoCoordinate sourceCoordinate = new GeoCoordinate(46.2044, 6.1432); - List stopConnections = routingController.getIsolines(null, sourceCoordinate.latitude(), - sourceCoordinate.longitude(), null, TimeType.ARRIVAL, 30, 2, 120, 5, true); + List stopConnections = getIsolines(null, sourceCoordinate.latitude(), + sourceCoordinate.longitude(), null, TimeType.ARRIVAL, true); // This tests if the time is set to now if null LocalDateTime expectedArrivalTime = LocalDateTime.now(); @@ -417,8 +459,7 @@ void testInvalidSourceStopId() { // Act & Assert ResponseStatusException exception = assertThrows(ResponseStatusException.class, - () -> routingController.getIsolines(invalidStopId, null, null, LocalDateTime.now(), - TimeType.DEPARTURE, 30, 2, 120, 5, false)); + () -> getIsolines(invalidStopId, null, null, LocalDateTime.now(), TimeType.DEPARTURE, false)); assertEquals("The requested source stop with ID 'invalidStopId' was not found.", exception.getReason()); assertEquals(HttpStatusCode.valueOf(404), exception.getStatusCode()); } @@ -427,8 +468,7 @@ void testInvalidSourceStopId() { void testMissingSourceStopAndSourceCoordinates() { // Act & Assert ResponseStatusException exception = assertThrows(ResponseStatusException.class, - () -> routingController.getIsolines(null, null, null, LocalDateTime.now(), TimeType.DEPARTURE, 30, - 2, 120, 5, false)); + () -> getIsolines(null, null, null, LocalDateTime.now(), TimeType.DEPARTURE, false)); assertEquals("Either sourceStopId or sourceLatitude and sourceLongitude must be provided.", exception.getReason()); assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); @@ -438,8 +478,7 @@ void testMissingSourceStopAndSourceCoordinates() { void testGivenSourceStopAndSourceCoordinates() { // Act & Assert ResponseStatusException exception = assertThrows(ResponseStatusException.class, - () -> routingController.getIsolines("sourceStopId", 0., 0.1, LocalDateTime.now(), - TimeType.DEPARTURE, 30, 2, 120, 5, false)); + () -> getIsolines("sourceStopId", 0., 0.1, LocalDateTime.now(), TimeType.DEPARTURE, false)); assertEquals("Only sourceStopId or sourceLatitude and sourceLongitude must be provided, but not both.", exception.getReason()); assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); @@ -449,52 +488,36 @@ void testGivenSourceStopAndSourceCoordinates() { void testInvalidCoordinates() { // Act & Assert ResponseStatusException exception = assertThrows(ResponseStatusException.class, - () -> routingController.getIsolines(null, 91., 181., LocalDateTime.now(), TimeType.DEPARTURE, 30, 2, - 120, 5, false)); + () -> getIsolines(null, 91., 181., LocalDateTime.now(), TimeType.DEPARTURE, false)); assertEquals("Coordinates must be valid, Latitude between -90 and 90 and Longitude between -180 and 180.", exception.getReason()); assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); } - @Test - void testInvalidMaxTransferNumber() { - // Act & Assert - ResponseStatusException exception = assertThrows(ResponseStatusException.class, - () -> routingController.getIsolines(null, 0., 0., LocalDateTime.now(), TimeType.DEPARTURE, 30, -2, - 120, 5, false)); - assertEquals("Max transfer number must be greater than or equal to 0.", exception.getReason()); - assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); - } - - @Test - void testInvalidMaxWalkingDuration() { - // Act & Assert - ResponseStatusException exception = assertThrows(ResponseStatusException.class, - () -> routingController.getIsolines(null, 0., 0., LocalDateTime.now(), TimeType.DEPARTURE, -30, 2, - 120, 5, false)); - assertEquals("Max walking duration must be greater than or equal to 0.", exception.getReason()); - assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); - } - - @Test - void testInvalidMaxTravelTime() { - // Act & Assert - ResponseStatusException exception = assertThrows(ResponseStatusException.class, - () -> routingController.getIsolines(null, 0., 0., LocalDateTime.now(), TimeType.DEPARTURE, 30, 2, - -120, 5, false)); - assertEquals("Max travel time must be greater than 0.", exception.getReason()); - assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); - } - - @Test - void testInvalidMinTransferTime() { - // Act & Assert - ResponseStatusException exception = assertThrows(ResponseStatusException.class, - () -> routingController.getIsolines(null, 0., 0., LocalDateTime.now(), TimeType.DEPARTURE, 30, 2, - 120, -5, false)); - assertEquals("Min transfer time must be greater than or equal to 0.", exception.getReason()); - assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + @ParameterizedTest(name = "isolineQueryConfig_{0}") + @MethodSource("provideQueryConfigTestCombinations") + void testQueryConfigValues(String name, Integer maxWalkingDuration, Integer maxTransferDuration, + Integer maxTravelTime, int minTransferTime, boolean wheelChairAccessible, + boolean bikeAllowed, EnumSet travelModes, + boolean hasAccessibilityInformation, boolean hasBikeInformation, + boolean hasTravelModeInformation, String errorMessage) { + + dummyService.setHasAccessibilityInformation(hasAccessibilityInformation); + dummyService.setHasBikeInformation(hasBikeInformation); + dummyService.setHasTravelModeInformation(hasTravelModeInformation); + + if (errorMessage == null) { + routingController.getIsolines("A", null, null, LocalDateTime.now(), TimeType.DEPARTURE, + maxWalkingDuration, maxTransferDuration, maxTravelTime, minTransferTime, wheelChairAccessible, + bikeAllowed, travelModes, false); + } else { + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> routingController.getIsolines("A", null, null, LocalDateTime.now(), TimeType.DEPARTURE, + maxWalkingDuration, maxTransferDuration, maxTravelTime, minTransferTime, + wheelChairAccessible, bikeAllowed, travelModes, false)); + assertEquals(errorMessage, exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } } - } } diff --git a/src/test/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorServiceIT.java b/src/test/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorServiceIT.java index 48ee859c..211e85cb 100644 --- a/src/test/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorServiceIT.java +++ b/src/test/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorServiceIT.java @@ -191,7 +191,7 @@ class Routing { @BeforeEach void setUp() { - config = new ConnectionQueryConfig(10 * 60, 2 * 60, 4, 24 * 60 * 60); + config = new ConnectionQueryConfig(10 * 60, 2 * 60, 4, 24 * 60 * 60, false, false, null); } @Nested From 0c3a60c9c2cbe8b1b5a3be860eeb9846b2a0daa0 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Sat, 17 Aug 2024 00:52:05 +0200 Subject: [PATCH 07/51] TEST: NAV-131 - Add tests for new query config parameter values in routing controller. --- .../app/controller/RoutingControllerTest.java | 80 +++++++++++++++---- 1 file changed, 64 insertions(+), 16 deletions(-) diff --git a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java index 7ee88ef4..ac395b8a 100644 --- a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java +++ b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java @@ -34,31 +34,79 @@ static Stream provideQueryConfigTestCombinations() { boolean validBikeAllowed = false; EnumSet validTravelModes = EnumSet.allOf(TravelMode.class); + boolean hasAccessibilityInformation = true; + boolean hasBikeInformation = true; + boolean hasTravelModeInformation = true; + return Stream.of( Arguments.of("validValues", validMaxWalkingDuration, validMaxTransferDuration, validMaxTravelTime, - validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, true, true, - true, null), + validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, + hasAccessibilityInformation, hasBikeInformation, hasTravelModeInformation, null), Arguments.of("maxWalkingDurationEqualsNull", null, validMaxTransferDuration, validMaxTravelTime, - validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, true, true, - true, null), + validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, + hasAccessibilityInformation, hasBikeInformation, hasTravelModeInformation, null), Arguments.of("invalidMaxWalkingDuration", -1, validMaxTransferDuration, validMaxTravelTime, - validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, true, true, - true, "Max walking duration must be greater than or equal to 0."), + validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, + hasAccessibilityInformation, hasBikeInformation, hasTravelModeInformation, + "Max walking duration must be greater than or equal to 0."), Arguments.of("maxTransferDurationEqualsNull", validMaxWalkingDuration, null, validMaxTravelTime, - validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, true, true, - true, null), + validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, + hasAccessibilityInformation, hasBikeInformation, hasTravelModeInformation, null), Arguments.of("invalidMaxTransferDuration", validMaxWalkingDuration, -1, validMaxTravelTime, - validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, true, true, - true, "Max transfer number must be greater than or equal to 0."), + validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, + hasAccessibilityInformation, hasBikeInformation, hasTravelModeInformation, + "Max transfer number must be greater than or equal to 0."), Arguments.of("maxTravelTimeEqualsNull", validMaxWalkingDuration, validMaxTransferDuration, null, - validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, true, true, - true, null), + validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, + hasAccessibilityInformation, hasBikeInformation, hasTravelModeInformation, null), Arguments.of("invalidMaxTravelTime", validMaxWalkingDuration, validMaxTransferDuration, -1, - validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, true, true, - true, "Max travel time must be greater than 0."), + validMinTransferTime, validWheelChairAccessible, validBikeAllowed, validTravelModes, + hasAccessibilityInformation, hasBikeInformation, hasTravelModeInformation, + "Max travel time must be greater than 0."), Arguments.of("invalidMinTransferTime", validMaxWalkingDuration, validMaxTransferDuration, - validMaxTravelTime, -1, validWheelChairAccessible, validBikeAllowed, validTravelModes, true, - true, true, "Min transfer time must be greater than or equal to 0.")); + validMaxTravelTime, -1, validWheelChairAccessible, validBikeAllowed, validTravelModes, + hasAccessibilityInformation, hasBikeInformation, hasTravelModeInformation, + "Min transfer time must be greater than or equal to 0."), + Arguments.of("wheelchairAccessibleWhenServiceProvidesNoSupport", validMaxWalkingDuration, + validMaxTransferDuration, validMaxTravelTime, validMinTransferTime, true, validBikeAllowed, + validTravelModes, false, hasBikeInformation, hasTravelModeInformation, + "Accessibility information is not available for this service."), + Arguments.of("bikeAllowedWhenServiceProvidesNoSupport", validMaxWalkingDuration, + validMaxTransferDuration, validMaxTravelTime, validMinTransferTime, validWheelChairAccessible, + true, validTravelModes, hasAccessibilityInformation, false, hasTravelModeInformation, + "Bike information is not available for this service."), + Arguments.of("travelModesWhenServiceProvidesNoSupport", validMaxWalkingDuration, + validMaxTransferDuration, validMaxTravelTime, validMinTransferTime, validWheelChairAccessible, + validBikeAllowed, EnumSet.of(TravelMode.BUS), hasAccessibilityInformation, hasBikeInformation, + false, "Service does not support travel mode information."), + Arguments.of("wheelchairAccessibleWhenServiceProvidesSupport", validMaxWalkingDuration, + validMaxTransferDuration, validMaxTravelTime, validMinTransferTime, true, validBikeAllowed, + validTravelModes, hasAccessibilityInformation, hasBikeInformation, hasTravelModeInformation, + null), + Arguments.of("bikeAllowedWhenServiceProvidesSupport", validMaxWalkingDuration, validMaxTransferDuration, + validMaxTravelTime, validMinTransferTime, validWheelChairAccessible, hasTravelModeInformation, + validTravelModes, hasAccessibilityInformation, hasBikeInformation, hasTravelModeInformation, + null), + Arguments.of("travelModesWhenServiceProvidesSupport", validMaxWalkingDuration, validMaxTransferDuration, + validMaxTravelTime, validMinTransferTime, validWheelChairAccessible, validBikeAllowed, + EnumSet.of(TravelMode.BUS), hasAccessibilityInformation, hasBikeInformation, + hasTravelModeInformation, null), + Arguments.of("defaultWheelchairAccessibleWhenNoSupport", validMaxWalkingDuration, + validMaxTransferDuration, validMaxTravelTime, validMinTransferTime, false, validBikeAllowed, + validTravelModes, false, hasBikeInformation, hasTravelModeInformation, null), + Arguments.of("defaultBikeAllowedWhenNoSupport", validMaxWalkingDuration, validMaxTransferDuration, + validMaxTravelTime, validMinTransferTime, validWheelChairAccessible, false, validTravelModes, + hasAccessibilityInformation, false, hasTravelModeInformation, null), + Arguments.of("defaultTravelModesWhenNoSupport", validMaxWalkingDuration, validMaxTransferDuration, + validMaxTravelTime, validMinTransferTime, validWheelChairAccessible, validBikeAllowed, + EnumSet.allOf(TravelMode.class), hasAccessibilityInformation, hasBikeInformation, false, null), + Arguments.of("emptyTravelModesWhenNoSupport", validMaxWalkingDuration, validMaxTransferDuration, + validMaxTravelTime, validMinTransferTime, validWheelChairAccessible, validBikeAllowed, + EnumSet.noneOf(TravelMode.class), hasAccessibilityInformation, hasBikeInformation, + hasTravelModeInformation, null), + Arguments.of("nullTravelModesWhenNoSupport", validMaxWalkingDuration, validMaxTransferDuration, + validMaxTravelTime, validMinTransferTime, validWheelChairAccessible, validBikeAllowed, null, + hasAccessibilityInformation, hasBikeInformation, hasTravelModeInformation, null)); } List getConnections(String sourceStopId, Double sourceLatitude, Double sourceLongitude, From f7ad46aac44a0fd31aff5a32070beff035b0ca61 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Sat, 17 Aug 2024 01:03:31 +0200 Subject: [PATCH 08/51] ENH: NAV-131 - Add router info endpoint. --- .../ch/naviqore/app/controller/RoutingController.java | 9 +++++++++ src/main/java/ch/naviqore/app/dto/RouterInfo.java | 10 ++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/main/java/ch/naviqore/app/dto/RouterInfo.java diff --git a/src/main/java/ch/naviqore/app/controller/RoutingController.java b/src/main/java/ch/naviqore/app/controller/RoutingController.java index 6b5fdd08..3b1e2048 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingController.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingController.java @@ -1,6 +1,7 @@ package ch.naviqore.app.controller; import ch.naviqore.app.dto.Connection; +import ch.naviqore.app.dto.RouterInfo; import ch.naviqore.app.dto.StopConnection; import ch.naviqore.service.*; import ch.naviqore.service.config.ConnectionQueryConfig; @@ -45,6 +46,14 @@ private static void handleConnectionRoutingException(ConnectionRoutingException throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()); } + @Operation(summary = "Get information about the routing service", description = "Get information about the routing service, such as supported features.") + @ApiResponse(responseCode = "200", description = "A list of features supported or not supported by the routing service.") + @GetMapping("/") + public RouterInfo getRouterInfo() { + return new RouterInfo(service.hasAccessibilityInformation(), service.hasBikeInformation(), + service.hasTravelModeInformation()); + } + @Operation(summary = "Request connections between two stops or locations", description = "Requests connections between two stops or locations at a given departure / arrival datetime.") @ApiResponse(responseCode = "200", description = "A list of connections between the specified stops.") @ApiResponse(responseCode = "400", description = "Invalid input parameters", content = @Content(schema = @Schema())) diff --git a/src/main/java/ch/naviqore/app/dto/RouterInfo.java b/src/main/java/ch/naviqore/app/dto/RouterInfo.java new file mode 100644 index 00000000..8986e819 --- /dev/null +++ b/src/main/java/ch/naviqore/app/dto/RouterInfo.java @@ -0,0 +1,10 @@ +package ch.naviqore.app.dto; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor() +public class RouterInfo { + final boolean supportsAccessibility; + final boolean supportsBikes; + final boolean supportsTravelModes; +} From 3f50d95f9a01fabcf8093b3e938df16df71f9968 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Sat, 17 Aug 2024 01:12:14 +0200 Subject: [PATCH 09/51] TEST: NAV-131 - Add test for router info endpoint. --- .../java/ch/naviqore/app/dto/RouterInfo.java | 6 +++- .../app/controller/RoutingControllerTest.java | 35 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/main/java/ch/naviqore/app/dto/RouterInfo.java b/src/main/java/ch/naviqore/app/dto/RouterInfo.java index 8986e819..6fb70d91 100644 --- a/src/main/java/ch/naviqore/app/dto/RouterInfo.java +++ b/src/main/java/ch/naviqore/app/dto/RouterInfo.java @@ -1,8 +1,12 @@ package ch.naviqore.app.dto; +import lombok.Getter; import lombok.RequiredArgsConstructor; +import lombok.ToString; -@RequiredArgsConstructor() +@RequiredArgsConstructor +@ToString +@Getter public class RouterInfo { final boolean supportsAccessibility; final boolean supportsBikes; diff --git a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java index ac395b8a..b56bbe07 100644 --- a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java +++ b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java @@ -568,4 +568,39 @@ void testQueryConfigValues(String name, Integer maxWalkingDuration, Integer maxT } } } + + @Nested + class RouterInfoEndpoint { + static Stream provideQueryConfigTestCombinations() { + boolean[] supportsAccessibility = {true, false}; + boolean[] supportsBikes = {true, false}; + boolean[] supportsTravelModes = {true, false}; + + // create all permutations based on the boolean arrays (not hard coded) + Stream stream = Stream.of(); + for (boolean supportsAccessibilityValue : supportsAccessibility) { + for (boolean supportsBikesValue : supportsBikes) { + for (boolean supportsTravelModesValue : supportsTravelModes) { + stream = Stream.concat(stream, Stream.of( + Arguments.of(supportsAccessibilityValue, supportsBikesValue, + supportsTravelModesValue))); + } + } + } + return stream; + } + + @ParameterizedTest(name = "routerInfoQueryConfig_{index}") + @MethodSource("provideQueryConfigTestCombinations") + void testQueryConfigValues(boolean supportsAccessibility, boolean supportsBikes, boolean supportsTravelModes) { + dummyService.setHasAccessibilityInformation(supportsAccessibility); + dummyService.setHasBikeInformation(supportsBikes); + dummyService.setHasTravelModeInformation(supportsTravelModes); + + RouterInfo routerInfo = routingController.getRouterInfo(); + assertEquals(supportsAccessibility, routerInfo.isSupportsAccessibility()); + assertEquals(supportsBikes, routerInfo.isSupportsBikes()); + assertEquals(supportsTravelModes, routerInfo.isSupportsTravelModes()); + } + } } From ee3418f64be1e98d9cb44608f8bb3337be5ab177 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Sat, 17 Aug 2024 10:41:55 +0200 Subject: [PATCH 10/51] ENH: NAV-131 - Add TravelMode Enum on Raptor level. --- src/main/java/ch/naviqore/raptor/TravelMode.java | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/main/java/ch/naviqore/raptor/TravelMode.java diff --git a/src/main/java/ch/naviqore/raptor/TravelMode.java b/src/main/java/ch/naviqore/raptor/TravelMode.java new file mode 100644 index 00000000..1a73d9b6 --- /dev/null +++ b/src/main/java/ch/naviqore/raptor/TravelMode.java @@ -0,0 +1,11 @@ +package ch.naviqore.raptor; + +public enum TravelMode { + BUS, + TRAM, + RAIL, + SHIP, + SUBWAY, + AERIAL_LIFT, + FUNICULAR, +} From 3d6cb0e1b4ed5445e59db755f3186aeaa87c6ece Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Sat, 17 Aug 2024 10:44:59 +0200 Subject: [PATCH 11/51] ENH: NAV-131 - Extend service mappers for service/raptor travelmodes and gtfs defaultroutetype. --- .../service/gtfs/raptor/TypeMapper.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/TypeMapper.java b/src/main/java/ch/naviqore/service/gtfs/raptor/TypeMapper.java index 3601592b..f05c0f03 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/TypeMapper.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/TypeMapper.java @@ -1,6 +1,7 @@ package ch.naviqore.service.gtfs.raptor; import ch.naviqore.gtfs.schedule.model.GtfsSchedule; +import ch.naviqore.gtfs.schedule.type.DefaultRouteType; import ch.naviqore.raptor.QueryConfig; import ch.naviqore.service.*; import ch.naviqore.service.config.ConnectionQueryConfig; @@ -15,6 +16,7 @@ import java.time.LocalDateTime; import java.time.LocalTime; import java.util.ArrayList; +import java.util.EnumSet; import java.util.List; @NoArgsConstructor(access = AccessLevel.NONE) @@ -119,6 +121,43 @@ public static ch.naviqore.raptor.TimeType map(TimeType timeType) { }; } + public static EnumSet map(EnumSet travelModes) { + EnumSet raptorTravelModes = EnumSet.noneOf(ch.naviqore.raptor.TravelMode.class); + for (TravelMode travelMode : travelModes) { + raptorTravelModes.add(ch.naviqore.raptor.TravelMode.valueOf(travelMode.name())); + } + return raptorTravelModes; + } + + public static EnumSet mapToRouteTypes(EnumSet travelModes) { + EnumSet routeTypes = EnumSet.noneOf(DefaultRouteType.class); + for (ch.naviqore.raptor.TravelMode travelMode : travelModes) { + routeTypes.addAll(map(travelMode)); + } + return routeTypes; + } + + public static EnumSet map(ch.naviqore.raptor.TravelMode travelMode) { + if (travelMode.equals(ch.naviqore.raptor.TravelMode.BUS)) { + return EnumSet.of(DefaultRouteType.BUS, DefaultRouteType.TROLLEYBUS); + } else if (travelMode.equals(ch.naviqore.raptor.TravelMode.TRAM)) { + return EnumSet.of(DefaultRouteType.TRAM, DefaultRouteType.CABLE_TRAM); + } else if (travelMode.equals(ch.naviqore.raptor.TravelMode.RAIL)) { + return EnumSet.of(DefaultRouteType.RAIL, DefaultRouteType.MONORAIL); + } else if (travelMode.equals(ch.naviqore.raptor.TravelMode.SHIP)) { + return EnumSet.of(DefaultRouteType.FERRY); + } else if (travelMode.equals(ch.naviqore.raptor.TravelMode.SUBWAY)) { + return EnumSet.of(DefaultRouteType.SUBWAY); + } else if (travelMode.equals(ch.naviqore.raptor.TravelMode.AERIAL_LIFT)) { + return EnumSet.of(DefaultRouteType.AERIAL_LIFT); + } else if (travelMode.equals(ch.naviqore.raptor.TravelMode.FUNICULAR)) { + return EnumSet.of(DefaultRouteType.FUNICULAR); + } else { + // should never happen + throw new IllegalArgumentException("Travel mode not supported"); + } + } + private static Leg createPublicTransitLeg(ch.naviqore.raptor.Leg leg, GtfsSchedule schedule, int distance) { ch.naviqore.gtfs.schedule.model.Trip gtfsTrip = schedule.getTrips().get(leg.getTripId()); LocalDate serviceDay = getServiceDay(leg, gtfsTrip); From b41af8455d5976bcef5a8aa30b6598357ecb6947 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Sat, 17 Aug 2024 11:30:23 +0200 Subject: [PATCH 12/51] ENH: NAV-131 - Extend raptor query config with more options. --- .../java/ch/naviqore/raptor/QueryConfig.java | 16 +++++++++++++++- .../naviqore/service/gtfs/raptor/TypeMapper.java | 3 ++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main/java/ch/naviqore/raptor/QueryConfig.java b/src/main/java/ch/naviqore/raptor/QueryConfig.java index a2f97b84..cffed08c 100644 --- a/src/main/java/ch/naviqore/raptor/QueryConfig.java +++ b/src/main/java/ch/naviqore/raptor/QueryConfig.java @@ -2,6 +2,9 @@ import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.EnumSet; /** * Configuration to query connections or iso-lines. Default values are set to infinity or zero, which means that no @@ -18,12 +21,23 @@ public class QueryConfig { private int maximumTransferNumber = INFINITY; private int maximumTravelTime = INFINITY; + @Setter + private boolean wheelchairAccessible = false; + @Setter + private boolean bikeAccessible = false; + @Setter + private EnumSet allowedTravelModes = EnumSet.allOf(TravelMode.class); + public QueryConfig(int maximumWalkingDuration, int minimumTransferDuration, int maximumTransferNumber, - int maximumTravelTime) { + int maximumTravelTime, boolean wheelchairAccessible, boolean bikeAccessible, + EnumSet allowedTravelModes) { this.setMaximumWalkingDuration(maximumWalkingDuration); this.setMinimumTransferDuration(minimumTransferDuration); this.setMaximumTransferNumber(maximumTransferNumber); this.setMaximumTravelTime(maximumTravelTime); + this.setWheelchairAccessible(wheelchairAccessible); + this.setBikeAccessible(bikeAccessible); + this.setAllowedTravelModes(allowedTravelModes); } public void setMaximumWalkingDuration(int maximumWalkingDuration) { diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/TypeMapper.java b/src/main/java/ch/naviqore/service/gtfs/raptor/TypeMapper.java index f05c0f03..fa76fd55 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/TypeMapper.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/TypeMapper.java @@ -111,7 +111,8 @@ public static Leg map(ch.naviqore.raptor.Leg leg, GtfsSchedule schedule) { public static QueryConfig map(ConnectionQueryConfig config) { return new QueryConfig(config.getMaximumWalkingDuration(), config.getMinimumTransferDuration(), - config.getMaximumTransferNumber(), config.getMaximumTravelTime()); + config.getMaximumTransferNumber(), config.getMaximumTravelTime(), config.isWheelchairAccessible(), + config.isBikeAllowed(), map(config.getTravelModes())); } public static ch.naviqore.raptor.TimeType map(TimeType timeType) { From 3f2e13ea3e50a820bba7fc8522954ed8fda16bb3 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Sat, 17 Aug 2024 11:46:54 +0200 Subject: [PATCH 13/51] ENH: NAV-131 - Pass QueryConfig to TripMaskProvider and allow caching stop time array with specific query settings. --- .../java/ch/naviqore/raptor/router/Query.java | 2 +- .../naviqore/raptor/router/RaptorConfig.java | 3 ++- .../raptor/router/RaptorTripMaskProvider.java | 11 +++++---- .../naviqore/raptor/router/RouteScanner.java | 24 ++++++++++--------- .../raptor/router/StopTimeProvider.java | 16 +++++++++---- .../raptor/convert/GtfsTripMaskProvider.java | 3 ++- .../router/RaptorRouterMultiDayTest.java | 3 ++- 7 files changed, 39 insertions(+), 23 deletions(-) diff --git a/src/main/java/ch/naviqore/raptor/router/Query.java b/src/main/java/ch/naviqore/raptor/router/Query.java index 921bcee2..cd99d6fb 100644 --- a/src/main/java/ch/naviqore/raptor/router/Query.java +++ b/src/main/java/ch/naviqore/raptor/router/Query.java @@ -70,7 +70,7 @@ class Query { // set up footpath relaxer and route scanner and inject stop labels and times footpathRelaxer = new FootpathRelaxer(queryState, raptorData, config.getMinimumTransferDuration(), config.getMaximumWalkingDuration(), timeType); - routeScanner = new RouteScanner(queryState, raptorData, config.getMinimumTransferDuration(), timeType, + routeScanner = new RouteScanner(queryState, raptorData, config, timeType, referenceDate, raptorConfig.getDaysToScan()); } diff --git a/src/main/java/ch/naviqore/raptor/router/RaptorConfig.java b/src/main/java/ch/naviqore/raptor/router/RaptorConfig.java index 57f49669..bb73e099 100644 --- a/src/main/java/ch/naviqore/raptor/router/RaptorConfig.java +++ b/src/main/java/ch/naviqore/raptor/router/RaptorConfig.java @@ -1,5 +1,6 @@ package ch.naviqore.raptor.router; +import ch.naviqore.raptor.QueryConfig; import ch.naviqore.utils.cache.EvictionCache; import lombok.Getter; import lombok.NoArgsConstructor; @@ -80,7 +81,7 @@ public String getServiceIdForDate(LocalDate date) { } @Override - public DayTripMask getDayTripMask(LocalDate date) { + public DayTripMask getDayTripMask(LocalDate date, QueryConfig queryConfig) { Map tripMasks = new HashMap<>(); for (Map.Entry entry : tripIds.entrySet()) { String routeId = entry.getKey(); diff --git a/src/main/java/ch/naviqore/raptor/router/RaptorTripMaskProvider.java b/src/main/java/ch/naviqore/raptor/router/RaptorTripMaskProvider.java index dd58fb7a..6612dd3b 100644 --- a/src/main/java/ch/naviqore/raptor/router/RaptorTripMaskProvider.java +++ b/src/main/java/ch/naviqore/raptor/router/RaptorTripMaskProvider.java @@ -1,5 +1,7 @@ package ch.naviqore.raptor.router; +import ch.naviqore.raptor.QueryConfig; + import java.time.LocalDate; import java.util.Map; @@ -32,14 +34,15 @@ public interface RaptorTripMaskProvider { String getServiceIdForDate(LocalDate date); /** - * Get the trip mask for a given date. + * Get the trip mask for a given date and query config. *

- * This method should return a map of route ids to trip masks for the given date. + * This method should return a map of route ids to trip masks for the given date and query config. * - * @param date the date for which the trip mask should be returned. + * @param date the date for which the trip mask should be returned. + * @param queryConfig the query config for which the trip mask should be returned. * @return the raptor day mask of the day. */ - DayTripMask getDayTripMask(LocalDate date); + DayTripMask getDayTripMask(LocalDate date, QueryConfig queryConfig); /** * This represents a service day trip mask for a given day. diff --git a/src/main/java/ch/naviqore/raptor/router/RouteScanner.java b/src/main/java/ch/naviqore/raptor/router/RouteScanner.java index 7081a411..38f175c0 100644 --- a/src/main/java/ch/naviqore/raptor/router/RouteScanner.java +++ b/src/main/java/ch/naviqore/raptor/router/RouteScanner.java @@ -1,5 +1,6 @@ package ch.naviqore.raptor.router; +import ch.naviqore.raptor.QueryConfig; import ch.naviqore.raptor.TimeType; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.Nullable; @@ -37,14 +38,14 @@ class RouteScanner { private final int startDayOffset; /** - * @param queryState the query state with the best time per stop and label per stop and round. - * @param raptorData the current raptor data structures. - * @param minimumTransferDuration The minimum transfer duration time. - * @param timeType the time type (arrival or departure). - * @param referenceDateTime the reference date for the query. - * @param maxDaysToScan the maximum number of days to scan. + * @param queryState the query state with the best time per stop and label per stop and round. + * @param raptorData the current raptor data structures. + * @param queryConfig the query config. + * @param timeType the time type (arrival or departure). + * @param referenceDateTime the reference date for the query. + * @param maxDaysToScan the maximum number of days to scan. */ - RouteScanner(QueryState queryState, RaptorData raptorData, int minimumTransferDuration, TimeType timeType, + RouteScanner(QueryState queryState, RaptorData raptorData, QueryConfig queryConfig, TimeType timeType, LocalDateTime referenceDateTime, int maxDaysToScan) { // constant data structures this.stops = raptorData.getStopContext().stops(); @@ -55,7 +56,7 @@ class RouteScanner { // note: will also change outside of scanner, due to footpath relaxation this.queryState = queryState; // constant configuration of scanner - this.minTransferDuration = minimumTransferDuration; + this.minTransferDuration = queryConfig.getMinimumTransferDuration(); this.timeType = timeType; LocalDate referenceDate = referenceDateTime.toLocalDate(); @@ -64,14 +65,15 @@ class RouteScanner { throw new IllegalArgumentException("maxDaysToScan must be greater than 0."); } else if (maxDaysToScan == 1) { stopTimes = new int[1][]; - stopTimes[0] = raptorData.getStopTimeProvider().getStopTimesForDate(referenceDate); + stopTimes[0] = raptorData.getStopTimeProvider().getStopTimesForDate(referenceDate, queryConfig); actualDaysToScan = 1; startDayOffset = 0; } else { // there is no need to scan the next day for arrival trips but previous day is maybe needed in departure trips if (timeType == TimeType.DEPARTURE) { LocalDate previousDay = referenceDate.minusDays(1); - int[] previousDayStopTimes = raptorData.getStopTimeProvider().getStopTimesForDate(previousDay); + int[] previousDayStopTimes = raptorData.getStopTimeProvider() + .getStopTimesForDate(previousDay, queryConfig); int departureTimeInPreviousDaySeconds = (int) Duration.between(previousDay.atStartOfDay(), referenceDateTime).getSeconds(); @@ -95,7 +97,7 @@ class RouteScanner { int dayOffset = i + startDayOffset; LocalDate date = timeType == TimeType.DEPARTURE ? referenceDate.plusDays( dayOffset) : referenceDate.minusDays(dayOffset); - stopTimes[i] = raptorData.getStopTimeProvider().getStopTimesForDate(date); + stopTimes[i] = raptorData.getStopTimeProvider().getStopTimesForDate(date, queryConfig); } } } diff --git a/src/main/java/ch/naviqore/raptor/router/StopTimeProvider.java b/src/main/java/ch/naviqore/raptor/router/StopTimeProvider.java index c1bcc20d..ad247f58 100644 --- a/src/main/java/ch/naviqore/raptor/router/StopTimeProvider.java +++ b/src/main/java/ch/naviqore/raptor/router/StopTimeProvider.java @@ -1,5 +1,6 @@ package ch.naviqore.raptor.router; +import ch.naviqore.raptor.QueryConfig; import ch.naviqore.utils.cache.EvictionCache; import java.time.LocalDate; @@ -48,13 +49,20 @@ class StopTimeProvider { * @param date the date for which the stop times should be created (or retrieved from cache) * @return the stop times for the given date. */ - int[] getStopTimesForDate(LocalDate date) { + int[] getStopTimesForDate(LocalDate date, QueryConfig queryConfig) { + String stopTimesKey = getCacheKeyForStopTimes(date, queryConfig); + return stopTimeCache.computeIfAbsent(stopTimesKey, () -> createStopTimesForDate(date, queryConfig)); + } + + private String getCacheKeyForStopTimes(LocalDate date, QueryConfig queryConfig) { String serviceId = tripMaskProvider.getServiceIdForDate(date); - return stopTimeCache.computeIfAbsent(serviceId, () -> createStopTimesForDate(date)); + String queryConfigKey = String.format("%b-%b-%s", queryConfig.isWheelchairAccessible(), + queryConfig.isBikeAccessible(), queryConfig.getAllowedTravelModes()); + return serviceId + "-" + queryConfigKey; } - private int[] createStopTimesForDate(LocalDate date) { - RaptorTripMaskProvider.DayTripMask mask = tripMaskProvider.getDayTripMask(date); + private int[] createStopTimesForDate(LocalDate date, QueryConfig queryConfig) { + RaptorTripMaskProvider.DayTripMask mask = tripMaskProvider.getDayTripMask(date, queryConfig); int[] originalStopTimesArray = data.getRouteTraversal().stopTimes(); int[] newStopTimesArray = new int[originalStopTimesArray.length]; diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java b/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java index 94c6d6a7..9862842e 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java @@ -1,6 +1,7 @@ package ch.naviqore.service.gtfs.raptor.convert; import ch.naviqore.gtfs.schedule.model.GtfsSchedule; +import ch.naviqore.raptor.QueryConfig; import ch.naviqore.raptor.router.RaptorTripMaskProvider; import ch.naviqore.service.config.ServiceConfig; import ch.naviqore.utils.cache.EvictionCache; @@ -38,7 +39,7 @@ public String getServiceIdForDate(LocalDate date) { } @Override - public DayTripMask getDayTripMask(LocalDate date) { + public DayTripMask getDayTripMask(LocalDate date, QueryConfig queryConfig) { if (tripIds == null) { throw new IllegalStateException("Trip ids not set"); } diff --git a/src/test/java/ch/naviqore/raptor/router/RaptorRouterMultiDayTest.java b/src/test/java/ch/naviqore/raptor/router/RaptorRouterMultiDayTest.java index a82be763..23e76750 100644 --- a/src/test/java/ch/naviqore/raptor/router/RaptorRouterMultiDayTest.java +++ b/src/test/java/ch/naviqore/raptor/router/RaptorRouterMultiDayTest.java @@ -1,6 +1,7 @@ package ch.naviqore.raptor.router; import ch.naviqore.raptor.Connection; +import ch.naviqore.raptor.QueryConfig; import ch.naviqore.raptor.RaptorAlgorithm; import lombok.NoArgsConstructor; import lombok.Setter; @@ -52,7 +53,7 @@ public String getServiceIdForDate(LocalDate date) { } @Override - public DayTripMask getDayTripMask(LocalDate date) { + public DayTripMask getDayTripMask(LocalDate date, QueryConfig queryConfig) { Set blockedRouteIds = blockedRoutes.getOrDefault(date, Set.of()); From 6d3a3539b200dbc882f6b79ddaee62a7961030b0 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Sat, 17 Aug 2024 11:53:02 +0200 Subject: [PATCH 14/51] FIX: NAV-131 - Add default query config when preparing stop time arrays for a given date. --- src/main/java/ch/naviqore/raptor/router/RaptorRouter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ch/naviqore/raptor/router/RaptorRouter.java b/src/main/java/ch/naviqore/raptor/router/RaptorRouter.java index 4f778125..58d125c8 100644 --- a/src/main/java/ch/naviqore/raptor/router/RaptorRouter.java +++ b/src/main/java/ch/naviqore/raptor/router/RaptorRouter.java @@ -49,7 +49,7 @@ class RaptorRouter implements RaptorAlgorithm, RaptorData { @Override public void prepareStopTimesForDate(LocalDate date) { - stopTimeProvider.getStopTimesForDate(date); + stopTimeProvider.getStopTimesForDate(date, new QueryConfig()); } @Override From d65a4fe7a26a5e29446ce04f9f071794b6773682 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Sat, 17 Aug 2024 13:22:39 +0200 Subject: [PATCH 15/51] FIX: NAV-131 - Handle cases correctly where travelmodes are null or empty in mapper. --- .../java/ch/naviqore/service/gtfs/raptor/TypeMapper.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/TypeMapper.java b/src/main/java/ch/naviqore/service/gtfs/raptor/TypeMapper.java index fa76fd55..68a760ab 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/TypeMapper.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/TypeMapper.java @@ -123,6 +123,9 @@ public static ch.naviqore.raptor.TimeType map(TimeType timeType) { } public static EnumSet map(EnumSet travelModes) { + if (travelModes == null || travelModes.isEmpty()) { + return EnumSet.allOf(ch.naviqore.raptor.TravelMode.class); + } EnumSet raptorTravelModes = EnumSet.noneOf(ch.naviqore.raptor.TravelMode.class); for (TravelMode travelMode : travelModes) { raptorTravelModes.add(ch.naviqore.raptor.TravelMode.valueOf(travelMode.name())); @@ -131,6 +134,9 @@ public static EnumSet map(EnumSet tra } public static EnumSet mapToRouteTypes(EnumSet travelModes) { + if (travelModes == null || travelModes.isEmpty()) { + return EnumSet.allOf(DefaultRouteType.class); + } EnumSet routeTypes = EnumSet.noneOf(DefaultRouteType.class); for (ch.naviqore.raptor.TravelMode travelMode : travelModes) { routeTypes.addAll(map(travelMode)); From 216098f09d500640af1a7cf33979bde00108190d Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Sat, 17 Aug 2024 14:08:37 +0200 Subject: [PATCH 16/51] ENH: NAV-131 - Add trip masking based on gtfs schedule and query config. --- .../service/gtfs/raptor/TypeMapper.java | 33 -------- .../raptor/convert/GtfsTripMaskProvider.java | 83 ++++++++++++++++++- 2 files changed, 80 insertions(+), 36 deletions(-) diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/TypeMapper.java b/src/main/java/ch/naviqore/service/gtfs/raptor/TypeMapper.java index 68a760ab..481b8c37 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/TypeMapper.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/TypeMapper.java @@ -1,7 +1,6 @@ package ch.naviqore.service.gtfs.raptor; import ch.naviqore.gtfs.schedule.model.GtfsSchedule; -import ch.naviqore.gtfs.schedule.type.DefaultRouteType; import ch.naviqore.raptor.QueryConfig; import ch.naviqore.service.*; import ch.naviqore.service.config.ConnectionQueryConfig; @@ -133,38 +132,6 @@ public static EnumSet map(EnumSet tra return raptorTravelModes; } - public static EnumSet mapToRouteTypes(EnumSet travelModes) { - if (travelModes == null || travelModes.isEmpty()) { - return EnumSet.allOf(DefaultRouteType.class); - } - EnumSet routeTypes = EnumSet.noneOf(DefaultRouteType.class); - for (ch.naviqore.raptor.TravelMode travelMode : travelModes) { - routeTypes.addAll(map(travelMode)); - } - return routeTypes; - } - - public static EnumSet map(ch.naviqore.raptor.TravelMode travelMode) { - if (travelMode.equals(ch.naviqore.raptor.TravelMode.BUS)) { - return EnumSet.of(DefaultRouteType.BUS, DefaultRouteType.TROLLEYBUS); - } else if (travelMode.equals(ch.naviqore.raptor.TravelMode.TRAM)) { - return EnumSet.of(DefaultRouteType.TRAM, DefaultRouteType.CABLE_TRAM); - } else if (travelMode.equals(ch.naviqore.raptor.TravelMode.RAIL)) { - return EnumSet.of(DefaultRouteType.RAIL, DefaultRouteType.MONORAIL); - } else if (travelMode.equals(ch.naviqore.raptor.TravelMode.SHIP)) { - return EnumSet.of(DefaultRouteType.FERRY); - } else if (travelMode.equals(ch.naviqore.raptor.TravelMode.SUBWAY)) { - return EnumSet.of(DefaultRouteType.SUBWAY); - } else if (travelMode.equals(ch.naviqore.raptor.TravelMode.AERIAL_LIFT)) { - return EnumSet.of(DefaultRouteType.AERIAL_LIFT); - } else if (travelMode.equals(ch.naviqore.raptor.TravelMode.FUNICULAR)) { - return EnumSet.of(DefaultRouteType.FUNICULAR); - } else { - // should never happen - throw new IllegalArgumentException("Travel mode not supported"); - } - } - private static Leg createPublicTransitLeg(ch.naviqore.raptor.Leg leg, GtfsSchedule schedule, int distance) { ch.naviqore.gtfs.schedule.model.Trip gtfsTrip = schedule.getTrips().get(leg.getTripId()); LocalDate serviceDay = getServiceDay(leg, gtfsTrip); diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java b/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java index 9862842e..662d56d9 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java @@ -1,13 +1,21 @@ package ch.naviqore.service.gtfs.raptor.convert; import ch.naviqore.gtfs.schedule.model.GtfsSchedule; +import ch.naviqore.gtfs.schedule.model.Route; +import ch.naviqore.gtfs.schedule.model.Trip; +import ch.naviqore.gtfs.schedule.type.AccessibilityInformation; +import ch.naviqore.gtfs.schedule.type.BikeInformation; +import ch.naviqore.gtfs.schedule.type.DefaultRouteType; +import ch.naviqore.gtfs.schedule.type.RouteTypeMapper; import ch.naviqore.raptor.QueryConfig; +import ch.naviqore.raptor.TravelMode; import ch.naviqore.raptor.router.RaptorTripMaskProvider; import ch.naviqore.service.config.ServiceConfig; import ch.naviqore.utils.cache.EvictionCache; import lombok.Setter; import java.time.LocalDate; +import java.util.EnumSet; import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; @@ -29,6 +37,38 @@ public GtfsTripMaskProvider(GtfsSchedule schedule, int cacheSize, EvictionCache. this.cache = new GtfsTripMaskProvider.MaskCache(cacheSize, strategy); } + private static EnumSet mapToRouteTypes(EnumSet travelModes) { + if (travelModes == null || travelModes.isEmpty()) { + return EnumSet.allOf(DefaultRouteType.class); + } + EnumSet routeTypes = EnumSet.noneOf(DefaultRouteType.class); + for (TravelMode travelMode : travelModes) { + routeTypes.addAll(map(travelMode)); + } + return routeTypes; + } + + private static EnumSet map(TravelMode travelMode) { + if (travelMode.equals(TravelMode.BUS)) { + return EnumSet.of(DefaultRouteType.BUS, DefaultRouteType.TROLLEYBUS); + } else if (travelMode.equals(TravelMode.TRAM)) { + return EnumSet.of(DefaultRouteType.TRAM, DefaultRouteType.CABLE_TRAM); + } else if (travelMode.equals(TravelMode.RAIL)) { + return EnumSet.of(DefaultRouteType.RAIL, DefaultRouteType.MONORAIL); + } else if (travelMode.equals(TravelMode.SHIP)) { + return EnumSet.of(DefaultRouteType.FERRY); + } else if (travelMode.equals(TravelMode.SUBWAY)) { + return EnumSet.of(DefaultRouteType.SUBWAY); + } else if (travelMode.equals(TravelMode.AERIAL_LIFT)) { + return EnumSet.of(DefaultRouteType.AERIAL_LIFT); + } else if (travelMode.equals(TravelMode.FUNICULAR)) { + return EnumSet.of(DefaultRouteType.FUNICULAR); + } else { + // should never happen + throw new IllegalArgumentException("Travel mode not supported"); + } + } + public void clearCache() { cache.clear(); } @@ -43,18 +83,55 @@ public DayTripMask getDayTripMask(LocalDate date, QueryConfig queryConfig) { if (tripIds == null) { throw new IllegalStateException("Trip ids not set"); } - return buildTripMask(date, cache.getActiveServices(date)); + return buildTripMask(date, cache.getActiveServices(date), queryConfig); } - private DayTripMask buildTripMask(LocalDate date, String serviceId) { + private DayTripMask buildTripMask(LocalDate date, String serviceId, QueryConfig queryConfig) { Map tripMasks = new HashMap<>(); + boolean hasNonDefaultTravelModeFilter = queryConfig.getAllowedTravelModes() + .size() != TravelMode.values().length; + EnumSet allowedRouteTypes = mapToRouteTypes(queryConfig.getAllowedTravelModes()); + for (Map.Entry entry : tripIds.entrySet()) { String routeId = entry.getKey(); String[] tripIds = entry.getValue(); + boolean[] tripMask = new boolean[tripIds.length]; + + // only check route type if there is a non-default travel mode filter + if (hasNonDefaultTravelModeFilter) { + Route route = schedule.getRoutes().get(routeId); + DefaultRouteType routeType = RouteTypeMapper.map(route.getType()); + if (!allowedRouteTypes.contains(routeType)) { + // no need for further checks if route type is not allowed + tripMasks.put(routeId, new RouteTripMask(tripMask)); + continue; + } + } + for (int i = 0; i < tripIds.length; i++) { - tripMask[i] = schedule.getTrips().get(tripIds[i]).getCalendar().isServiceAvailable(date); + Trip trip = schedule.getTrips().get(tripIds[i]); + if (!trip.getCalendar().isServiceAvailable(date)) { + tripMask[i] = false; + continue; + } + + if (queryConfig.isWheelchairAccessible()) { + if (trip.getWheelchairAccessible() != AccessibilityInformation.ACCESSIBLE) { + tripMask[i] = false; + continue; + } + } + + if (queryConfig.isBikeAccessible()) { + if (trip.getBikesAllowed() != BikeInformation.ALLOWED) { + tripMask[i] = false; + continue; + } + } + + tripMask[i] = true; } tripMasks.put(routeId, new RouteTripMask(tripMask)); From 8d9a3ae824de342d415bc4dec8a0504e247faea6 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Sun, 18 Aug 2024 00:15:42 +0200 Subject: [PATCH 17/51] FIX: NAV-131 - Define GTFS Service accessibility information with trips. --- .../java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java b/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java index 82b83373..a8552af2 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java @@ -61,7 +61,7 @@ public class GtfsRaptorService implements PublicTransitService { @Override public boolean hasAccessibilityInformation() { - return schedule.hasStopAccessibilityInformation(); + return schedule.hasTripAccessibilityInformation(); } @Override From d63c0b6a1abebf8b9c8aee43dab25c0e92eb59a5 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Sun, 18 Aug 2024 00:16:19 +0200 Subject: [PATCH 18/51] FIX: NAV-131 - Get route through trip instead (sub)route id in gtfs mask provider. --- .../service/gtfs/raptor/convert/GtfsTripMaskProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java b/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java index 662d56d9..dc7c5781 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java @@ -101,7 +101,8 @@ private DayTripMask buildTripMask(LocalDate date, String serviceId, QueryConfig // only check route type if there is a non-default travel mode filter if (hasNonDefaultTravelModeFilter) { - Route route = schedule.getRoutes().get(routeId); + Trip firstTripOfRoute = schedule.getTrips().get(tripIds[0]); + Route route = firstTripOfRoute.getRoute(); DefaultRouteType routeType = RouteTypeMapper.map(route.getType()); if (!allowedRouteTypes.contains(routeType)) { // no need for further checks if route type is not allowed From 8f163289f773062a61f3149d010cedb6d2ba0ba1 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Sun, 18 Aug 2024 12:21:51 +0200 Subject: [PATCH 19/51] TEST: NAV-131 - Add tests for GtfsTripMaskProvider. --- .../convert/GtfsTripMaskProviderTest.java | 203 ++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 src/test/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProviderTest.java diff --git a/src/test/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProviderTest.java b/src/test/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProviderTest.java new file mode 100644 index 00000000..c35d6048 --- /dev/null +++ b/src/test/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProviderTest.java @@ -0,0 +1,203 @@ +package ch.naviqore.service.gtfs.raptor.convert; + +import ch.naviqore.gtfs.schedule.model.GtfsSchedule; +import ch.naviqore.gtfs.schedule.model.GtfsScheduleBuilder; +import ch.naviqore.gtfs.schedule.type.*; +import ch.naviqore.raptor.QueryConfig; +import ch.naviqore.raptor.TravelMode; +import ch.naviqore.raptor.router.RaptorTripMaskProvider; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.util.*; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class GtfsTripMaskProviderTest { + + private static final LocalDate WEEKDAY = LocalDate.of(2020, 1, 2); + private static final LocalDate WEEKEND = LocalDate.of(2020, 1, 4); + private static final LocalDate EXCEPTION = LocalDate.of(2020, 1, 1); + + static Stream provideTestCases() { + List argumentsList = new ArrayList<>(); + argumentsList.add( + Arguments.of("Weekday, all travel modes, all accessibility, all bike", WEEKDAY, new QueryConfig())); + argumentsList.add( + Arguments.of("Weekend, all travel modes, all accessibility, all bike", WEEKEND, new QueryConfig())); + argumentsList.add( + Arguments.of("Exception, all travel modes, all accessibility, all bike", EXCEPTION, new QueryConfig())); + + QueryConfig queryConfig = new QueryConfig(); + queryConfig.setAllowedTravelModes(EnumSet.of(TravelMode.BUS)); + argumentsList.add(Arguments.of("Weekday, bus only, all accessibility, all bike", WEEKDAY, queryConfig)); + + queryConfig = new QueryConfig(); + queryConfig.setAllowedTravelModes(EnumSet.of(TravelMode.BUS, TravelMode.TRAM)); + argumentsList.add(Arguments.of("Weekday, bus and tram, all accessibility, all bike", WEEKDAY, queryConfig)); + + queryConfig = new QueryConfig(); + queryConfig.setWheelchairAccessible(true); + argumentsList.add(Arguments.of("Weekday, all travel modes, accessible only, all bike", WEEKDAY, queryConfig)); + + queryConfig = new QueryConfig(); + queryConfig.setBikeAccessible(true); + argumentsList.add( + Arguments.of("Weekday, all travel modes, all accessibility, bike allowed", WEEKDAY, queryConfig)); + + queryConfig = new QueryConfig(); + queryConfig.setAllowedTravelModes(EnumSet.of(TravelMode.BUS)); + queryConfig.setWheelchairAccessible(true); + queryConfig.setBikeAccessible(true); + argumentsList.add(Arguments.of("Weekday, bus only, accessible only, bike allowed", WEEKDAY, queryConfig)); + + return argumentsList.stream(); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("provideTestCases") + void testMasks(String name, LocalDate date, QueryConfig queryConfig) { + GtfsTripMaskProvider provider = new GtfsTripMaskProvider(Utilities.prepareSchedule()); + provider.setTripIds(Utilities.getTripIds()); + + List expectedRoutes = queryConfig.getAllowedTravelModes() + .stream() + .map(Utilities.TRAVEL_MODE_MAP::get) + .filter(Objects::nonNull) + .toList(); + + String[] expectedServiceIds = date.equals(WEEKDAY) ? new String[]{"weekdays"} : date.equals( + WEEKEND) ? new String[]{"weekends"} : new String[]{"exception"}; + + AccessibilityInformation[] expectedAccessibilityValues = queryConfig.isWheelchairAccessible() ? new AccessibilityInformation[]{ + AccessibilityInformation.ACCESSIBLE} : Utilities.ACCESSIBILITY_VALUES; + + BikeInformation[] expectedBikeValues = queryConfig.isBikeAccessible() ? new BikeInformation[]{ + BikeInformation.ALLOWED} : Utilities.BIKE_VALUES; + + boolean[] expectedTripMask = Utilities.getExpectedTripMask(expectedServiceIds, expectedAccessibilityValues, + expectedBikeValues); + + Map tripMasks = provider.getDayTripMask(date, queryConfig) + .tripMask(); + + // check that all routes are present + for (String routeId : Utilities.ROUTE_IDS) { + assertTrue(tripMasks.containsKey(routeId), "Route " + routeId + " is missing in the trip mask"); + } + + for (Map.Entry entry : tripMasks.entrySet()) { + String routeId = entry.getKey(); + RaptorTripMaskProvider.RouteTripMask routeTripMask = entry.getValue(); + boolean[] tripMask = routeTripMask.routeTripMask(); + + if (expectedRoutes.contains(routeId)) { + assertArrayEquals(expectedTripMask, tripMask, "Trip mask for route " + routeId + " does not match"); + } else { + assertArrayEquals(new boolean[Utilities.NUM_TRIPS_PER_ROUTE], tripMask, + "Trip mask for route " + routeId + " should have no active trips"); + } + } + } + + static class Utilities { + + private static final String[] ROUTE_IDS = {"route1", "route2", "route3"}; + private static final String[] SERVICE_IDS = {"weekdays", "weekends", "exception"}; + private static final AccessibilityInformation[] ACCESSIBILITY_VALUES = {AccessibilityInformation.UNKNOWN, + AccessibilityInformation.ACCESSIBLE, AccessibilityInformation.NOT_ACCESSIBLE}; + private static final BikeInformation[] BIKE_VALUES = {BikeInformation.UNKNOWN, BikeInformation.ALLOWED, + BikeInformation.NOT_ALLOWED}; + private static final int NUM_TRIPS_PER_ROUTE = SERVICE_IDS.length * ACCESSIBILITY_VALUES.length * BIKE_VALUES.length; + private static final Map TRAVEL_MODE_MAP = Map.of(TravelMode.BUS, "route1", TravelMode.TRAM, + "route2", TravelMode.RAIL, "route3"); + + private static GtfsSchedule prepareSchedule() { + GtfsScheduleBuilder builder = GtfsSchedule.builder(); + + builder.addAgency("agency1", "Agency 1", "abc", "Europe/Zurich"); + builder.addStop("stop1", "Stop 1", 47.0, 8.0); + builder.addStop("stop2", "Stop 2", 47.1, 8.1); + + builder.addRoute("route1", "agency1", "Route 1", "Route 1 - Bus", HierarchicalVehicleType.BUS_SERVICE); + builder.addRoute("route2", "agency1", "Route 2", "Route 2 - Tram", HierarchicalVehicleType.TRAM_SERVICE); + builder.addRoute("route3", "agency1", "Route 3", "Route 3 - Rail", HierarchicalVehicleType.RAILWAY_SERVICE); + + builder.addCalendar("weekdays", EnumSet.range(DayOfWeek.MONDAY, DayOfWeek.FRIDAY), LocalDate.MIN, + LocalDate.MAX); + builder.addCalendar("weekends", EnumSet.of(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY), LocalDate.MIN, + LocalDate.MAX); + // January 1st, 2020 is a Wednesday (weekday) + builder.addCalendarDate("exception", LocalDate.of(2020, 1, 1), ExceptionType.ADDED); + builder.addCalendarDate("weekdays", LocalDate.of(2020, 1, 1), ExceptionType.REMOVED); + + for (String routeId : ROUTE_IDS) { + for (int tripCounter = 0; tripCounter < NUM_TRIPS_PER_ROUTE; tripCounter++) { + String serviceId = getServiceIdForTripIndex(tripCounter); + AccessibilityInformation accessibilityValue = getAccessibilityInformation(tripCounter); + BikeInformation bikeValue = getBikeInformation(tripCounter); + String tripId = getTripId(routeId, tripCounter); + + builder.addTrip(tripId, routeId, serviceId, tripId, accessibilityValue, bikeValue); + builder.addStopTime(tripId, "stop1", new ServiceDayTime(0), new ServiceDayTime(0)); + builder.addStopTime(tripId, "stop2", new ServiceDayTime(60), new ServiceDayTime(60)); + } + } + return builder.build(); + } + + private static boolean[] getExpectedTripMask(String[] serviceIds, + AccessibilityInformation[] accessibilityValues, + BikeInformation[] bikeValues) { + boolean[] expectedTripMask = new boolean[NUM_TRIPS_PER_ROUTE]; + for (int tripCounter = 0; tripCounter < NUM_TRIPS_PER_ROUTE; tripCounter++) { + if (!Arrays.asList(serviceIds).contains(getServiceIdForTripIndex(tripCounter))) { + continue; + } + if (!Arrays.asList(accessibilityValues).contains(getAccessibilityInformation(tripCounter))) { + continue; + } + if (!Arrays.asList(bikeValues).contains(getBikeInformation(tripCounter))) { + continue; + } + expectedTripMask[tripCounter] = true; + } + return expectedTripMask; + } + + private static Map getTripIds() { + Map tripMap = new HashMap<>(); + for (String routeId : ROUTE_IDS) { + String[] tripIds = new String[NUM_TRIPS_PER_ROUTE]; + for (int tripCounter = 0; tripCounter < NUM_TRIPS_PER_ROUTE; tripCounter++) { + tripIds[tripCounter] = getTripId(routeId, tripCounter); + } + tripMap.put(routeId, tripIds); + } + return tripMap; + } + + private static String getServiceIdForTripIndex(int tripIndex) { + return SERVICE_IDS[tripIndex % SERVICE_IDS.length]; + } + + private static AccessibilityInformation getAccessibilityInformation(int tripIndex) { + return ACCESSIBILITY_VALUES[(tripIndex / SERVICE_IDS.length) % ACCESSIBILITY_VALUES.length]; + } + + private static BikeInformation getBikeInformation(int tripIndex) { + return BIKE_VALUES[(tripIndex / (SERVICE_IDS.length * ACCESSIBILITY_VALUES.length)) % BIKE_VALUES.length]; + } + + private static String getTripId(String routeId, int tripIndex) { + return routeId + "-trip" + tripIndex; + } + + } + +} \ No newline at end of file From ae802f23b587e1ec0056fbc8a2e0c9dfec799896 Mon Sep 17 00:00:00 2001 From: Merlin Unterfinger Date: Mon, 19 Aug 2024 12:05:15 +0200 Subject: [PATCH 20/51] STYLE: NAV-131 - Format project and cosmetics - Rename endpoint for RoutingInfo from "/routing/" to "/routing", so it appears on top in the Swagger UI. --- .../ch/naviqore/app/controller/RoutingController.java | 2 +- src/main/java/ch/naviqore/app/dto/RouterInfo.java | 2 ++ src/main/java/ch/naviqore/raptor/router/Query.java | 4 ++-- .../java/ch/naviqore/app/controller/DummyService.java | 9 ++++----- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/ch/naviqore/app/controller/RoutingController.java b/src/main/java/ch/naviqore/app/controller/RoutingController.java index 3b1e2048..3f53dcbc 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingController.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingController.java @@ -48,7 +48,7 @@ private static void handleConnectionRoutingException(ConnectionRoutingException @Operation(summary = "Get information about the routing service", description = "Get information about the routing service, such as supported features.") @ApiResponse(responseCode = "200", description = "A list of features supported or not supported by the routing service.") - @GetMapping("/") + @GetMapping("") public RouterInfo getRouterInfo() { return new RouterInfo(service.hasAccessibilityInformation(), service.hasBikeInformation(), service.hasTravelModeInformation()); diff --git a/src/main/java/ch/naviqore/app/dto/RouterInfo.java b/src/main/java/ch/naviqore/app/dto/RouterInfo.java index 6fb70d91..1fae6154 100644 --- a/src/main/java/ch/naviqore/app/dto/RouterInfo.java +++ b/src/main/java/ch/naviqore/app/dto/RouterInfo.java @@ -8,7 +8,9 @@ @ToString @Getter public class RouterInfo { + final boolean supportsAccessibility; final boolean supportsBikes; final boolean supportsTravelModes; + } diff --git a/src/main/java/ch/naviqore/raptor/router/Query.java b/src/main/java/ch/naviqore/raptor/router/Query.java index cd99d6fb..1145a45c 100644 --- a/src/main/java/ch/naviqore/raptor/router/Query.java +++ b/src/main/java/ch/naviqore/raptor/router/Query.java @@ -70,8 +70,8 @@ class Query { // set up footpath relaxer and route scanner and inject stop labels and times footpathRelaxer = new FootpathRelaxer(queryState, raptorData, config.getMinimumTransferDuration(), config.getMaximumWalkingDuration(), timeType); - routeScanner = new RouteScanner(queryState, raptorData, config, timeType, - referenceDate, raptorConfig.getDaysToScan()); + routeScanner = new RouteScanner(queryState, raptorData, config, timeType, referenceDate, + raptorConfig.getDaysToScan()); } /** diff --git a/src/test/java/ch/naviqore/app/controller/DummyService.java b/src/test/java/ch/naviqore/app/controller/DummyService.java index 4525251c..6d4b54e2 100644 --- a/src/test/java/ch/naviqore/app/controller/DummyService.java +++ b/src/test/java/ch/naviqore/app/controller/DummyService.java @@ -19,10 +19,6 @@ @NoArgsConstructor class DummyService implements PublicTransitService { - private boolean hasAccessibilityInformation; - private boolean hasBikeInformation; - private boolean hasTravelModeInformation; - static final DummyServiceModels.Stop STOP_A = new DummyServiceModels.Stop("A", "Stop A", new GeoCoordinate(0, 0)); static final DummyServiceModels.Stop STOP_B = new DummyServiceModels.Stop("B", "Stop B", new GeoCoordinate(1, 1)); static final DummyServiceModels.Stop STOP_C = new DummyServiceModels.Stop("C", "Stop C", new GeoCoordinate(2, 2)); @@ -31,7 +27,6 @@ class DummyService implements PublicTransitService { static final DummyServiceModels.Stop STOP_F = new DummyServiceModels.Stop("F", "Stop F", new GeoCoordinate(5, 5)); static final DummyServiceModels.Stop STOP_G = new DummyServiceModels.Stop("G", "Stop G", new GeoCoordinate(6, 6)); static final DummyServiceModels.Stop STOP_H = new DummyServiceModels.Stop("H", "Stop H", new GeoCoordinate(7, 7)); - static final List STOPS = List.of(STOP_A, STOP_B, STOP_C, STOP_D, STOP_E, STOP_F, STOP_G, STOP_H); private static final RouteData ROUTE_1 = new RouteData( @@ -45,6 +40,10 @@ class DummyService implements PublicTransitService { List.of(STOP_D, STOP_E, STOP_F, STOP_G, STOP_H)); static final List ROUTES = List.of(ROUTE_1, ROUTE_2, ROUTE_3); + private boolean hasAccessibilityInformation; + private boolean hasBikeInformation; + private boolean hasTravelModeInformation; + @Override public Validity getValidity() { return new Validity() { From 9da1a5a35253b4aaca165b9ea3236dd4c81acb4b Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Wed, 21 Aug 2024 21:50:06 +0200 Subject: [PATCH 21/51] ENH: NAV-131 - Add schedule validity to schedule info endpoint and rename routerInfo to scheduleInfo. --- .../app/controller/RoutingController.java | 9 --------- .../app/controller/ScheduleController.java | 8 ++++++++ src/main/java/ch/naviqore/app/dto/DtoMapper.java | 4 ++++ .../dto/{RouterInfo.java => ScheduleInfo.java} | 3 ++- .../ch/naviqore/app/dto/ScheduleValidity.java | 15 +++++++++++++++ .../app/controller/RoutingControllerTest.java | 2 +- 6 files changed, 30 insertions(+), 11 deletions(-) rename src/main/java/ch/naviqore/app/dto/{RouterInfo.java => ScheduleInfo.java} (78%) create mode 100644 src/main/java/ch/naviqore/app/dto/ScheduleValidity.java diff --git a/src/main/java/ch/naviqore/app/controller/RoutingController.java b/src/main/java/ch/naviqore/app/controller/RoutingController.java index 3b1e2048..6b5fdd08 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingController.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingController.java @@ -1,7 +1,6 @@ package ch.naviqore.app.controller; import ch.naviqore.app.dto.Connection; -import ch.naviqore.app.dto.RouterInfo; import ch.naviqore.app.dto.StopConnection; import ch.naviqore.service.*; import ch.naviqore.service.config.ConnectionQueryConfig; @@ -46,14 +45,6 @@ private static void handleConnectionRoutingException(ConnectionRoutingException throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()); } - @Operation(summary = "Get information about the routing service", description = "Get information about the routing service, such as supported features.") - @ApiResponse(responseCode = "200", description = "A list of features supported or not supported by the routing service.") - @GetMapping("/") - public RouterInfo getRouterInfo() { - return new RouterInfo(service.hasAccessibilityInformation(), service.hasBikeInformation(), - service.hasTravelModeInformation()); - } - @Operation(summary = "Request connections between two stops or locations", description = "Requests connections between two stops or locations at a given departure / arrival datetime.") @ApiResponse(responseCode = "200", description = "A list of connections between the specified stops.") @ApiResponse(responseCode = "400", description = "Invalid input parameters", content = @Content(schema = @Schema())) diff --git a/src/main/java/ch/naviqore/app/controller/ScheduleController.java b/src/main/java/ch/naviqore/app/controller/ScheduleController.java index 953e50da..acb38db8 100644 --- a/src/main/java/ch/naviqore/app/controller/ScheduleController.java +++ b/src/main/java/ch/naviqore/app/controller/ScheduleController.java @@ -30,6 +30,14 @@ public ScheduleController(ScheduleInformationService service) { this.service = service; } + @Operation(summary = "Get information about the schedule", description = "Get all relevant information about the schedule, such as supported features and validity.") + @ApiResponse(responseCode = "200", description = "A list of details supported or not supported by the schedule and it's validity.") + @GetMapping("/") + public ScheduleInfo getScheduleInfo() { + return new ScheduleInfo(service.hasAccessibilityInformation(), service.hasBikeInformation(), + service.hasTravelModeInformation(), map(service.getValidity())); + } + @Operation(summary = "Autocomplete stop names", description = "Provides stop names and their corresponding stop IDs based on a partial input query.") @ApiResponse(responseCode = "200", description = "A list of stop names and IDs that match the query", content = @Content(schema = @Schema(implementation = Stop.class, type = "array"))) @ApiResponse(responseCode = "400", description = "Invalid input parameters", content = @Content(schema = @Schema())) diff --git a/src/main/java/ch/naviqore/app/dto/DtoMapper.java b/src/main/java/ch/naviqore/app/dto/DtoMapper.java index 577e0e9c..55c27173 100644 --- a/src/main/java/ch/naviqore/app/dto/DtoMapper.java +++ b/src/main/java/ch/naviqore/app/dto/DtoMapper.java @@ -67,6 +67,10 @@ public static List map(Map { @Override public Leg visit(PublicTransitLeg publicTransitLeg) { diff --git a/src/main/java/ch/naviqore/app/dto/RouterInfo.java b/src/main/java/ch/naviqore/app/dto/ScheduleInfo.java similarity index 78% rename from src/main/java/ch/naviqore/app/dto/RouterInfo.java rename to src/main/java/ch/naviqore/app/dto/ScheduleInfo.java index 6fb70d91..365d035d 100644 --- a/src/main/java/ch/naviqore/app/dto/RouterInfo.java +++ b/src/main/java/ch/naviqore/app/dto/ScheduleInfo.java @@ -7,8 +7,9 @@ @RequiredArgsConstructor @ToString @Getter -public class RouterInfo { +public class ScheduleInfo { final boolean supportsAccessibility; final boolean supportsBikes; final boolean supportsTravelModes; + final ScheduleValidity scheduleValidity; } diff --git a/src/main/java/ch/naviqore/app/dto/ScheduleValidity.java b/src/main/java/ch/naviqore/app/dto/ScheduleValidity.java new file mode 100644 index 00000000..7f5038f8 --- /dev/null +++ b/src/main/java/ch/naviqore/app/dto/ScheduleValidity.java @@ -0,0 +1,15 @@ +package ch.naviqore.app.dto; + +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDate; + +@RequiredArgsConstructor(access = AccessLevel.PACKAGE) +public class ScheduleValidity { + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) + final LocalDate startDate; + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) + final LocalDate endDate; +} diff --git a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java index b56bbe07..b38d94eb 100644 --- a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java +++ b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java @@ -597,7 +597,7 @@ void testQueryConfigValues(boolean supportsAccessibility, boolean supportsBikes, dummyService.setHasBikeInformation(supportsBikes); dummyService.setHasTravelModeInformation(supportsTravelModes); - RouterInfo routerInfo = routingController.getRouterInfo(); + ScheduleInfo routerInfo = routingController.getRoutingInfo(); assertEquals(supportsAccessibility, routerInfo.isSupportsAccessibility()); assertEquals(supportsBikes, routerInfo.isSupportsBikes()); assertEquals(supportsTravelModes, routerInfo.isSupportsTravelModes()); From 06cbd7c0830c073fdcc82c89535b8c867d8478fa Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Wed, 21 Aug 2024 22:07:33 +0200 Subject: [PATCH 22/51] ENH: NAV-131 - Add getters to scheduleValidity. --- src/main/java/ch/naviqore/app/dto/ScheduleValidity.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/ch/naviqore/app/dto/ScheduleValidity.java b/src/main/java/ch/naviqore/app/dto/ScheduleValidity.java index 7f5038f8..c01179c7 100644 --- a/src/main/java/ch/naviqore/app/dto/ScheduleValidity.java +++ b/src/main/java/ch/naviqore/app/dto/ScheduleValidity.java @@ -1,12 +1,14 @@ package ch.naviqore.app.dto; import lombok.AccessLevel; +import lombok.Getter; import lombok.RequiredArgsConstructor; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDate; @RequiredArgsConstructor(access = AccessLevel.PACKAGE) +@Getter public class ScheduleValidity { @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) final LocalDate startDate; From 50bcbab1c6778234eb78449beafb1f01026b9fdb Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Wed, 21 Aug 2024 22:13:58 +0200 Subject: [PATCH 23/51] TEST: NAV-131 - Move schedule info test to scheduleControllerTest --- .../app/controller/RoutingControllerTest.java | 30 ------------ .../controller/ScheduleControllerTest.java | 46 +++++++++++++++++++ 2 files changed, 46 insertions(+), 30 deletions(-) diff --git a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java index b38d94eb..a762bff0 100644 --- a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java +++ b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java @@ -571,36 +571,6 @@ void testQueryConfigValues(String name, Integer maxWalkingDuration, Integer maxT @Nested class RouterInfoEndpoint { - static Stream provideQueryConfigTestCombinations() { - boolean[] supportsAccessibility = {true, false}; - boolean[] supportsBikes = {true, false}; - boolean[] supportsTravelModes = {true, false}; - - // create all permutations based on the boolean arrays (not hard coded) - Stream stream = Stream.of(); - for (boolean supportsAccessibilityValue : supportsAccessibility) { - for (boolean supportsBikesValue : supportsBikes) { - for (boolean supportsTravelModesValue : supportsTravelModes) { - stream = Stream.concat(stream, Stream.of( - Arguments.of(supportsAccessibilityValue, supportsBikesValue, - supportsTravelModesValue))); - } - } - } - return stream; - } - @ParameterizedTest(name = "routerInfoQueryConfig_{index}") - @MethodSource("provideQueryConfigTestCombinations") - void testQueryConfigValues(boolean supportsAccessibility, boolean supportsBikes, boolean supportsTravelModes) { - dummyService.setHasAccessibilityInformation(supportsAccessibility); - dummyService.setHasBikeInformation(supportsBikes); - dummyService.setHasTravelModeInformation(supportsTravelModes); - - ScheduleInfo routerInfo = routingController.getRoutingInfo(); - assertEquals(supportsAccessibility, routerInfo.isSupportsAccessibility()); - assertEquals(supportsBikes, routerInfo.isSupportsBikes()); - assertEquals(supportsTravelModes, routerInfo.isSupportsTravelModes()); - } } } diff --git a/src/test/java/ch/naviqore/app/controller/ScheduleControllerTest.java b/src/test/java/ch/naviqore/app/controller/ScheduleControllerTest.java index 8ff4800a..1455bbd8 100644 --- a/src/test/java/ch/naviqore/app/controller/ScheduleControllerTest.java +++ b/src/test/java/ch/naviqore/app/controller/ScheduleControllerTest.java @@ -13,7 +13,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.MethodSource; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @@ -23,6 +25,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; +import java.util.stream.Stream; import static ch.naviqore.app.dto.DtoMapper.map; import static org.junit.jupiter.api.Assertions.*; @@ -40,6 +43,49 @@ public class ScheduleControllerTest { @InjectMocks private ScheduleController scheduleController; + @Nested + class ScheduleInfo { + static Stream provideScheduleInfoTestCombinations() { + boolean[] supportsAccessibility = {true, false}; + boolean[] supportsBikes = {true, false}; + boolean[] supportsTravelModes = {true, false}; + + // create all permutations based on the boolean arrays (not hard coded) + Stream stream = Stream.of(); + for (boolean supportsAccessibilityValue : supportsAccessibility) { + for (boolean supportsBikesValue : supportsBikes) { + for (boolean supportsTravelModesValue : supportsTravelModes) { + stream = Stream.concat(stream, Stream.of( + Arguments.of(supportsAccessibilityValue, supportsBikesValue, + supportsTravelModesValue))); + } + } + } + return stream; + } + + @ParameterizedTest(name = "scheduleInfo_{index}") + @MethodSource("provideScheduleInfoTestCombinations") + void testQueryConfigValues(boolean supportsAccessibility, boolean supportsBikes, boolean supportsTravelModes) { + DummyService dummyService = new DummyService(); + dummyService.setHasAccessibilityInformation(supportsAccessibility); + dummyService.setHasBikeInformation(supportsBikes); + dummyService.setHasTravelModeInformation(supportsTravelModes); + + LocalDate expStartDate = dummyService.getValidity().getStartDate(); + LocalDate expEndDate = dummyService.getValidity().getEndDate(); + + ScheduleController scheduleController = new ScheduleController(dummyService); + + ch.naviqore.app.dto.ScheduleInfo routerInfo = scheduleController.getScheduleInfo(); + assertEquals(supportsAccessibility, routerInfo.isSupportsAccessibility()); + assertEquals(supportsBikes, routerInfo.isSupportsBikes()); + assertEquals(supportsTravelModes, routerInfo.isSupportsTravelModes()); + assertEquals(expStartDate, routerInfo.getScheduleValidity().getStartDate()); + assertEquals(expEndDate, routerInfo.getScheduleValidity().getEndDate()); + } + } + @Nested class AutoCompleteStops { From 71b7779c1eb4264003559f56b39106cd78c31ee4 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Wed, 21 Aug 2024 22:27:42 +0200 Subject: [PATCH 24/51] ENH: NAV-131 - Reintroduce TimeType enum on DTO level to keep separation of concerns. --- .../app/controller/RoutingController.java | 19 ++++++++++++------- .../java/ch/naviqore/app/dto/DtoMapper.java | 9 ++++++++- .../java/ch/naviqore/app/dto/TimeType.java | 6 ++++++ .../app/controller/RoutingControllerTest.java | 1 - 4 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 src/main/java/ch/naviqore/app/dto/TimeType.java diff --git a/src/main/java/ch/naviqore/app/controller/RoutingController.java b/src/main/java/ch/naviqore/app/controller/RoutingController.java index 6b5fdd08..5244b1ee 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingController.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingController.java @@ -2,7 +2,11 @@ import ch.naviqore.app.dto.Connection; import ch.naviqore.app.dto.StopConnection; -import ch.naviqore.service.*; +import ch.naviqore.app.dto.TimeType; +import ch.naviqore.service.PublicTransitService; +import ch.naviqore.service.ScheduleInformationService; +import ch.naviqore.service.Stop; +import ch.naviqore.service.TravelMode; import ch.naviqore.service.config.ConnectionQueryConfig; import ch.naviqore.service.exception.ConnectionRoutingException; import ch.naviqore.utils.spatial.GeoCoordinate; @@ -84,13 +88,13 @@ public List getConnections(@RequestParam(required = false) String so try { if (sourceStop != null && targetStop != null) { RoutingRequestValidator.validateStops(sourceStopId, targetStopId); - return map(service.getConnections(sourceStop, targetStop, dateTime, timeType, config)); + return map(service.getConnections(sourceStop, targetStop, dateTime, map(timeType), config)); } else if (sourceStop != null) { - return map(service.getConnections(sourceStop, targetCoordinate, dateTime, timeType, config)); + return map(service.getConnections(sourceStop, targetCoordinate, dateTime, map(timeType), config)); } else if (targetStop != null) { - return map(service.getConnections(sourceCoordinate, targetStop, dateTime, timeType, config)); + return map(service.getConnections(sourceCoordinate, targetStop, dateTime, map(timeType), config)); } else { - return map(service.getConnections(sourceCoordinate, targetCoordinate, dateTime, timeType, config)); + return map(service.getConnections(sourceCoordinate, targetCoordinate, dateTime, map(timeType), config)); } } catch (ConnectionRoutingException e) { handleConnectionRoutingException(e); @@ -130,9 +134,10 @@ public List getIsolines(@RequestParam(required = false) String s // determine routing case and get isolines try { if (sourceStop != null) { - return map(service.getIsoLines(sourceStop, dateTime, timeType, config), timeType, returnConnections); + return map(service.getIsoLines(sourceStop, dateTime, map(timeType), config), timeType, + returnConnections); } else { - return map(service.getIsoLines(sourceCoordinate, dateTime, timeType, config), timeType, + return map(service.getIsoLines(sourceCoordinate, dateTime, map(timeType), config), timeType, returnConnections); } } catch (ConnectionRoutingException e) { diff --git a/src/main/java/ch/naviqore/app/dto/DtoMapper.java b/src/main/java/ch/naviqore/app/dto/DtoMapper.java index 55c27173..5ebcf603 100644 --- a/src/main/java/ch/naviqore/app/dto/DtoMapper.java +++ b/src/main/java/ch/naviqore/app/dto/DtoMapper.java @@ -49,6 +49,13 @@ public static SearchType map(ch.naviqore.app.dto.SearchType searchType) { }; } + public static ch.naviqore.service.TimeType map(TimeType timeType) { + return switch (timeType) { + case ARRIVAL -> ch.naviqore.service.TimeType.ARRIVAL; + case DEPARTURE -> ch.naviqore.service.TimeType.DEPARTURE; + }; + } + public static Connection map(ch.naviqore.service.Connection connection) { List legs = connection.getLegs().stream().map(leg -> leg.accept(new LegVisitorImpl())).toList(); return new Connection(legs); @@ -62,7 +69,7 @@ public static List map(Map arrivals = new ArrayList<>(); for (Map.Entry entry : connections.entrySet()) { - arrivals.add(new StopConnection(entry.getKey(), entry.getValue(), timeType, returnConnections)); + arrivals.add(new StopConnection(entry.getKey(), entry.getValue(), map(timeType), returnConnections)); } return arrivals; } diff --git a/src/main/java/ch/naviqore/app/dto/TimeType.java b/src/main/java/ch/naviqore/app/dto/TimeType.java new file mode 100644 index 00000000..e71d6202 --- /dev/null +++ b/src/main/java/ch/naviqore/app/dto/TimeType.java @@ -0,0 +1,6 @@ +package ch.naviqore.app.dto; + +public enum TimeType { + ARRIVAL, + DEPARTURE +} diff --git a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java index a762bff0..0e3fcc30 100644 --- a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java +++ b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java @@ -1,7 +1,6 @@ package ch.naviqore.app.controller; import ch.naviqore.app.dto.*; -import ch.naviqore.service.TimeType; import ch.naviqore.service.TravelMode; import ch.naviqore.utils.spatial.GeoCoordinate; import org.junit.jupiter.api.Nested; From d7c147555e237d13045fb5bb7dfeeb288d73bb0f Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Wed, 21 Aug 2024 22:45:36 +0200 Subject: [PATCH 25/51] DOC: NAV-131 - Better explain when travel mode masking has to be done. --- .../gtfs/raptor/convert/GtfsTripMaskProvider.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java b/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java index dc7c5781..cdb52bf7 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java @@ -38,7 +38,7 @@ public GtfsTripMaskProvider(GtfsSchedule schedule, int cacheSize, EvictionCache. } private static EnumSet mapToRouteTypes(EnumSet travelModes) { - if (travelModes == null || travelModes.isEmpty()) { + if (travelModes.isEmpty()) { return EnumSet.allOf(DefaultRouteType.class); } EnumSet routeTypes = EnumSet.noneOf(DefaultRouteType.class); @@ -89,8 +89,9 @@ public DayTripMask getDayTripMask(LocalDate date, QueryConfig queryConfig) { private DayTripMask buildTripMask(LocalDate date, String serviceId, QueryConfig queryConfig) { Map tripMasks = new HashMap<>(); - boolean hasNonDefaultTravelModeFilter = queryConfig.getAllowedTravelModes() - .size() != TravelMode.values().length; + // the travel mode filter is only active if not all travel modes are allowed (no filtering is required when all + // travel modes are allowed) + boolean hasTravelModeFilter = queryConfig.getAllowedTravelModes().size() != TravelMode.values().length; EnumSet allowedRouteTypes = mapToRouteTypes(queryConfig.getAllowedTravelModes()); for (Map.Entry entry : tripIds.entrySet()) { @@ -99,8 +100,7 @@ private DayTripMask buildTripMask(LocalDate date, String serviceId, QueryConfig boolean[] tripMask = new boolean[tripIds.length]; - // only check route type if there is a non-default travel mode filter - if (hasNonDefaultTravelModeFilter) { + if (hasTravelModeFilter) { Trip firstTripOfRoute = schedule.getTrips().get(tripIds[0]); Route route = firstTripOfRoute.getRoute(); DefaultRouteType routeType = RouteTypeMapper.map(route.getType()); From 99962b75380e7d373753a3a5a45f47ac4f9d5379 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Wed, 21 Aug 2024 22:49:33 +0200 Subject: [PATCH 26/51] REFACTOR: NAV-131 - Flatten getCacheKEyForStopTimes. --- .../java/ch/naviqore/raptor/router/StopTimeProvider.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/ch/naviqore/raptor/router/StopTimeProvider.java b/src/main/java/ch/naviqore/raptor/router/StopTimeProvider.java index ad247f58..468e91b3 100644 --- a/src/main/java/ch/naviqore/raptor/router/StopTimeProvider.java +++ b/src/main/java/ch/naviqore/raptor/router/StopTimeProvider.java @@ -55,10 +55,9 @@ int[] getStopTimesForDate(LocalDate date, QueryConfig queryConfig) { } private String getCacheKeyForStopTimes(LocalDate date, QueryConfig queryConfig) { - String serviceId = tripMaskProvider.getServiceIdForDate(date); - String queryConfigKey = String.format("%b-%b-%s", queryConfig.isWheelchairAccessible(), - queryConfig.isBikeAccessible(), queryConfig.getAllowedTravelModes()); - return serviceId + "-" + queryConfigKey; + return String.format("%s-%b-%b-%s", tripMaskProvider.getServiceIdForDate(date), + queryConfig.isWheelchairAccessible(), queryConfig.isBikeAccessible(), + queryConfig.getAllowedTravelModes()); } private int[] createStopTimesForDate(LocalDate date, QueryConfig queryConfig) { From dd7190b0c05b1ff0d64c8e641eed4156390e1f5a Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Thu, 22 Aug 2024 12:34:15 +0200 Subject: [PATCH 27/51] ENH: NAV-131 - Make service use explicit implementation of raptor algorithm. --- .../java/ch/naviqore/raptor/RaptorAlgorithm.java | 4 ---- .../ch/naviqore/raptor/router/RaptorRouter.java | 6 +++++- .../raptor/router/RaptorRouterBuilder.java | 3 +-- .../service/gtfs/raptor/GtfsRaptorService.java | 14 +++++++------- .../gtfs/raptor/convert/GtfsToRaptorConverter.java | 5 +++-- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/main/java/ch/naviqore/raptor/RaptorAlgorithm.java b/src/main/java/ch/naviqore/raptor/RaptorAlgorithm.java index 33c36bf5..e44579e0 100644 --- a/src/main/java/ch/naviqore/raptor/RaptorAlgorithm.java +++ b/src/main/java/ch/naviqore/raptor/RaptorAlgorithm.java @@ -10,10 +10,6 @@ public interface RaptorAlgorithm { - static RaptorRouterBuilder builder(RaptorConfig config) { - return new RaptorRouterBuilder(config); - } - /** * Routing the earliest arrival from departure stops to arrival. Given a set departure time. * diff --git a/src/main/java/ch/naviqore/raptor/router/RaptorRouter.java b/src/main/java/ch/naviqore/raptor/router/RaptorRouter.java index 58d125c8..a0fdcd12 100644 --- a/src/main/java/ch/naviqore/raptor/router/RaptorRouter.java +++ b/src/main/java/ch/naviqore/raptor/router/RaptorRouter.java @@ -17,7 +17,7 @@ * Raptor algorithm implementation */ @Slf4j -class RaptorRouter implements RaptorAlgorithm, RaptorData { +public class RaptorRouter implements RaptorAlgorithm, RaptorData { @Getter private final Lookup lookup; @@ -47,6 +47,10 @@ class RaptorRouter implements RaptorAlgorithm, RaptorData { validator = new InputValidator(lookup.stops()); } + public static RaptorRouterBuilder builder(RaptorConfig config) { + return new RaptorRouterBuilder(config); + } + @Override public void prepareStopTimesForDate(LocalDate date) { stopTimeProvider.getStopTimesForDate(date, new QueryConfig()); diff --git a/src/main/java/ch/naviqore/raptor/router/RaptorRouterBuilder.java b/src/main/java/ch/naviqore/raptor/router/RaptorRouterBuilder.java index d2cc1d9d..827e6b13 100644 --- a/src/main/java/ch/naviqore/raptor/router/RaptorRouterBuilder.java +++ b/src/main/java/ch/naviqore/raptor/router/RaptorRouterBuilder.java @@ -1,6 +1,5 @@ package ch.naviqore.raptor.router; -import ch.naviqore.raptor.RaptorAlgorithm; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; @@ -108,7 +107,7 @@ public RaptorRouterBuilder addTransfer(String sourceStopId, String targetStopId, return this; } - public RaptorAlgorithm build() { + public RaptorRouter build() { log.info("Initializing Raptor with {} stops, {} routes, {} route stops, {} stop times, {} transfers", stops.size(), routeBuilders.size(), routeStopSize, stopTimeSize, transferSize); diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java b/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java index a8552af2..b5041f8f 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java @@ -1,8 +1,8 @@ package ch.naviqore.service.gtfs.raptor; import ch.naviqore.gtfs.schedule.model.GtfsSchedule; -import ch.naviqore.raptor.RaptorAlgorithm; import ch.naviqore.raptor.router.RaptorConfig; +import ch.naviqore.raptor.router.RaptorRouter; import ch.naviqore.service.*; import ch.naviqore.service.config.ConnectionQueryConfig; import ch.naviqore.service.config.ServiceConfig; @@ -35,7 +35,7 @@ public class GtfsRaptorService implements PublicTransitService { private final KDTree spatialStopIndex; private final SearchIndex stopSearchIndex; private final WalkCalculator walkCalculator; - private final RaptorAlgorithm raptorAlgorithm; + private final RaptorRouter raptorRouter; GtfsRaptorService(ServiceConfig config, GtfsSchedule schedule, KDTree spatialStopIndex, @@ -56,7 +56,7 @@ public class GtfsRaptorService implements PublicTransitService { RaptorConfig raptorConfig = new RaptorConfig(config.getRaptorDaysToScan(), config.getRaptorRange(), config.getTransferTimeSameStopDefault(), config.getCacheServiceDaySize(), cacheStrategy, tripMaskProvider); - raptorAlgorithm = new GtfsToRaptorConverter(schedule, additionalTransfers, raptorConfig).convert(); + raptorRouter = new GtfsToRaptorConverter(schedule, additionalTransfers, raptorConfig).convert(); } @Override @@ -214,9 +214,9 @@ private List getConnections(@Nullable ch.naviqore.gtfs.schedule.mode List connections; try { if (isDeparture) { - connections = raptorAlgorithm.routeEarliestArrival(sourceStops, targetStops, TypeMapper.map(config)); + connections = raptorRouter.routeEarliestArrival(sourceStops, targetStops, TypeMapper.map(config)); } else { - connections = raptorAlgorithm.routeLatestDeparture(targetStops, sourceStops, TypeMapper.map(config)); + connections = raptorRouter.routeLatestDeparture(targetStops, sourceStops, TypeMapper.map(config)); } } catch (IllegalArgumentException e) { throw new ConnectionRoutingException(e); @@ -310,7 +310,7 @@ public Map getIsoLines(GeoCoordinate source, LocalDateTime tim try { return mapToStopConnectionMap( - raptorAlgorithm.routeIsolines(sourceStops, TypeMapper.map(timeType), TypeMapper.map(config)), + raptorRouter.routeIsolines(sourceStops, TypeMapper.map(timeType), TypeMapper.map(config)), source, config, timeType); } catch (IllegalArgumentException e) { throw new ConnectionRoutingException(e); @@ -324,7 +324,7 @@ public Map getIsoLines(Stop source, LocalDateTime time, TimeTy try { return mapToStopConnectionMap( - raptorAlgorithm.routeIsolines(sourceStops, TypeMapper.map(timeType), TypeMapper.map(config)), null, + raptorRouter.routeIsolines(sourceStops, TypeMapper.map(timeType), TypeMapper.map(config)), null, config, timeType); } catch (IllegalArgumentException e) { throw new ConnectionRoutingException(e); diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsToRaptorConverter.java b/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsToRaptorConverter.java index 0d16f0a3..e3cb78f6 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsToRaptorConverter.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsToRaptorConverter.java @@ -7,6 +7,7 @@ import ch.naviqore.gtfs.schedule.type.TransferType; import ch.naviqore.raptor.RaptorAlgorithm; import ch.naviqore.raptor.router.RaptorConfig; +import ch.naviqore.raptor.router.RaptorRouter; import ch.naviqore.raptor.router.RaptorRouterBuilder; import ch.naviqore.service.gtfs.raptor.transfer.TransferGenerator; import lombok.extern.slf4j.Slf4j; @@ -43,10 +44,10 @@ public GtfsToRaptorConverter(GtfsSchedule schedule, List Date: Thu, 22 Aug 2024 12:36:44 +0200 Subject: [PATCH 28/51] REFACTOR: NAV-131 - Remove prepareStopTimesForDate from RaptorAlgorithm interface. --- src/main/java/ch/naviqore/raptor/RaptorAlgorithm.java | 3 --- src/main/java/ch/naviqore/raptor/router/RaptorRouter.java | 1 - src/test/java/ch/naviqore/Benchmark.java | 3 ++- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/ch/naviqore/raptor/RaptorAlgorithm.java b/src/main/java/ch/naviqore/raptor/RaptorAlgorithm.java index e44579e0..89c99313 100644 --- a/src/main/java/ch/naviqore/raptor/RaptorAlgorithm.java +++ b/src/main/java/ch/naviqore/raptor/RaptorAlgorithm.java @@ -46,7 +46,4 @@ List routeLatestDeparture(Map departureStops, Map routeIsolines(Map sourceStops, TimeType timeType, QueryConfig config); - // TODO: Discuss if this should be added to the interface (for now added for benchmark test) - void prepareStopTimesForDate(LocalDate date); - } diff --git a/src/main/java/ch/naviqore/raptor/router/RaptorRouter.java b/src/main/java/ch/naviqore/raptor/router/RaptorRouter.java index a0fdcd12..2c1c8638 100644 --- a/src/main/java/ch/naviqore/raptor/router/RaptorRouter.java +++ b/src/main/java/ch/naviqore/raptor/router/RaptorRouter.java @@ -51,7 +51,6 @@ public static RaptorRouterBuilder builder(RaptorConfig config) { return new RaptorRouterBuilder(config); } - @Override public void prepareStopTimesForDate(LocalDate date) { stopTimeProvider.getStopTimesForDate(date, new QueryConfig()); } diff --git a/src/test/java/ch/naviqore/Benchmark.java b/src/test/java/ch/naviqore/Benchmark.java index 07c7ecfc..97bb6b4a 100644 --- a/src/test/java/ch/naviqore/Benchmark.java +++ b/src/test/java/ch/naviqore/Benchmark.java @@ -10,6 +10,7 @@ import ch.naviqore.raptor.QueryConfig; import ch.naviqore.raptor.RaptorAlgorithm; import ch.naviqore.raptor.router.RaptorConfig; +import ch.naviqore.raptor.router.RaptorRouter; import ch.naviqore.service.gtfs.raptor.convert.GtfsToRaptorConverter; import ch.naviqore.service.gtfs.raptor.convert.GtfsTripMaskProvider; import ch.naviqore.utils.cache.EvictionCache; @@ -81,7 +82,7 @@ private static GtfsSchedule initializeSchedule() throws IOException, Interrupted private static RaptorAlgorithm initializeRaptor(GtfsSchedule schedule) throws InterruptedException { RaptorConfig config = new RaptorConfig(MAX_DAYS_TO_SCAN, RAPTOR_RANGE, SAME_STOP_TRANSFER_TIME, MAX_DAYS_TO_SCAN, EvictionCache.Strategy.LRU, new GtfsTripMaskProvider(schedule)); - RaptorAlgorithm raptor = new GtfsToRaptorConverter(schedule, config).convert(); + RaptorRouter raptor = new GtfsToRaptorConverter(schedule, config).convert(); manageResources(); for (int dayIndex = 0; dayIndex < MAX_DAYS_TO_SCAN; dayIndex++) { From 688d4f8c044031eed81c4b7a080871b5d4fe28b7 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Thu, 22 Aug 2024 12:45:14 +0200 Subject: [PATCH 29/51] REFACTOR: NAV-131 - Move logic whether travel mode filtering is needed to queryconfig class. --- src/main/java/ch/naviqore/raptor/QueryConfig.java | 12 ++++++++++++ .../gtfs/raptor/convert/GtfsTripMaskProvider.java | 4 +--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/ch/naviqore/raptor/QueryConfig.java b/src/main/java/ch/naviqore/raptor/QueryConfig.java index cffed08c..2e9256c5 100644 --- a/src/main/java/ch/naviqore/raptor/QueryConfig.java +++ b/src/main/java/ch/naviqore/raptor/QueryConfig.java @@ -68,4 +68,16 @@ public void setMaximumTravelTime(int maximumTravelTime) { this.maximumTravelTime = maximumTravelTime; } + /** + * Check if the query configuration needs filtering based on the allowed travel modes. + * + *

It is not necessary to filter if all travel modes are allowed. Also, if allowed travel modes are empty, it + * is assumed that all travel modes are allowed. + * + * @return true if the query configuration needs filtering based on the allowed travel modes, false otherwise. + */ + public boolean needsTravelModeFiltering() { + return allowedTravelModes.size() < TravelMode.values().length && !allowedTravelModes.isEmpty(); + } + } diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java b/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java index cdb52bf7..0ffc4e48 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java @@ -89,9 +89,7 @@ public DayTripMask getDayTripMask(LocalDate date, QueryConfig queryConfig) { private DayTripMask buildTripMask(LocalDate date, String serviceId, QueryConfig queryConfig) { Map tripMasks = new HashMap<>(); - // the travel mode filter is only active if not all travel modes are allowed (no filtering is required when all - // travel modes are allowed) - boolean hasTravelModeFilter = queryConfig.getAllowedTravelModes().size() != TravelMode.values().length; + boolean hasTravelModeFilter = queryConfig.needsTravelModeFiltering(); EnumSet allowedRouteTypes = mapToRouteTypes(queryConfig.getAllowedTravelModes()); for (Map.Entry entry : tripIds.entrySet()) { From f4523c3ef56186fdc7f66c3b066e34ce335c2fe1 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Thu, 22 Aug 2024 12:46:29 +0200 Subject: [PATCH 30/51] ENH: NAV-131 - Add validation of query configs before creating trip masks. --- .../gtfs/raptor/convert/GtfsTripMaskProvider.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java b/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java index 0ffc4e48..1a8d6be5 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsTripMaskProvider.java @@ -87,6 +87,7 @@ public DayTripMask getDayTripMask(LocalDate date, QueryConfig queryConfig) { } private DayTripMask buildTripMask(LocalDate date, String serviceId, QueryConfig queryConfig) { + validateQueryConfig(queryConfig); Map tripMasks = new HashMap<>(); boolean hasTravelModeFilter = queryConfig.needsTravelModeFiltering(); @@ -139,6 +140,15 @@ private DayTripMask buildTripMask(LocalDate date, String serviceId, QueryConfig return new DayTripMask(serviceId, date, tripMasks); } + private void validateQueryConfig(QueryConfig queryConfig) { + if (queryConfig.isWheelchairAccessible() && !schedule.hasTripAccessibilityInformation()) { + throw new IllegalArgumentException("GTFS schedule does not contain wheelchair accessibility information"); + } + if (queryConfig.isBikeAccessible() && !schedule.hasTripBikeInformation()) { + throw new IllegalArgumentException("GTFS schedule does not contain bike accessibility information"); + } + } + /** * Caches for active services (= GTFS calendars) per date and raptor trip mask instances. */ From 1e64db3d92035ce0d29ed4369bd3e62ed13c23f8 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Thu, 22 Aug 2024 15:49:06 +0200 Subject: [PATCH 31/51] ENH: NAV-131 - Add SupportedRoutingFeatures. --- .../service/ConnectionRoutingService.java | 7 +++++++ .../service/SupportedRoutingFeatures.java | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/main/java/ch/naviqore/service/SupportedRoutingFeatures.java diff --git a/src/main/java/ch/naviqore/service/ConnectionRoutingService.java b/src/main/java/ch/naviqore/service/ConnectionRoutingService.java index 34307041..571979f8 100644 --- a/src/main/java/ch/naviqore/service/ConnectionRoutingService.java +++ b/src/main/java/ch/naviqore/service/ConnectionRoutingService.java @@ -10,6 +10,13 @@ public interface ConnectionRoutingService { + /** + * Retrieves the supported routing features of the service. + * + * @return the supported routing features + */ + SupportedRoutingFeatures getSupportedRoutingFeatures(); + /** * Retrieves possible connections between two locations at a specified time. * diff --git a/src/main/java/ch/naviqore/service/SupportedRoutingFeatures.java b/src/main/java/ch/naviqore/service/SupportedRoutingFeatures.java new file mode 100644 index 00000000..24b93438 --- /dev/null +++ b/src/main/java/ch/naviqore/service/SupportedRoutingFeatures.java @@ -0,0 +1,18 @@ +package ch.naviqore.service; + +/** + * Supported routing features of the service. + * + * @param supportsMaxNumTransfers whether the service supports routing with a defined max number of transfers + * @param supportsMaxTravelTime whether the service supports routing with a defined max travel time (including waiting + * time) + * @param supportsMaxWalkingTime whether the service supports routing with a defined max walking time + * @param supportsMinTransferTime whether the service supports routing with a defined min transfer time + * @param supportsWheelchair whether the service supports routing for wheelchair users + * @param supportsBike whether the service supports routing for bike users + * @param supportsTravelMode whether the service supports routing for different travel modes + */ +public record SupportedRoutingFeatures(boolean supportsMaxNumTransfers, boolean supportsMaxTravelTime, + boolean supportsMaxWalkingTime, boolean supportsMinTransferTime, + boolean supportsWheelchair, boolean supportsBike, boolean supportsTravelMode) { +} From 674107fc04e3d4f806efb7086d73250182d4d61a Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Thu, 22 Aug 2024 15:51:41 +0200 Subject: [PATCH 32/51] ENH: NAV-131 - Implement get supported routing features. --- .../app/service/PublicTransitSpringService.java | 5 +++++ .../service/gtfs/raptor/GtfsRaptorService.java | 10 ++++++++-- .../ch/naviqore/app/controller/DummyService.java | 12 ++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/main/java/ch/naviqore/app/service/PublicTransitSpringService.java b/src/main/java/ch/naviqore/app/service/PublicTransitSpringService.java index 46ad68c1..504d30c0 100644 --- a/src/main/java/ch/naviqore/app/service/PublicTransitSpringService.java +++ b/src/main/java/ch/naviqore/app/service/PublicTransitSpringService.java @@ -91,6 +91,11 @@ public List getNextDepartures(Stop stop, LocalDateTime from, @Nullable return delegate.getNextDepartures(stop, from, until, limit); } + @Override + public SupportedRoutingFeatures getSupportedRoutingFeatures() { + return delegate.getSupportedRoutingFeatures(); + } + @Override public List getConnections(GeoCoordinate source, GeoCoordinate target, LocalDateTime time, TimeType timeType, diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java b/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java index b5041f8f..0b8895c0 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java @@ -153,6 +153,12 @@ public List getConnections(Stop source, Stop target, LocalDateTime t null, time, timeType, config); } + @Override + public SupportedRoutingFeatures getSupportedRoutingFeatures() { + return new SupportedRoutingFeatures(true, true, true, true, schedule.hasTripAccessibilityInformation(), + schedule.hasTripBikeInformation(), true ); + } + @Override public List getConnections(GeoCoordinate source, GeoCoordinate target, LocalDateTime time, TimeType timeType, @@ -310,8 +316,8 @@ public Map getIsoLines(GeoCoordinate source, LocalDateTime tim try { return mapToStopConnectionMap( - raptorRouter.routeIsolines(sourceStops, TypeMapper.map(timeType), TypeMapper.map(config)), - source, config, timeType); + raptorRouter.routeIsolines(sourceStops, TypeMapper.map(timeType), TypeMapper.map(config)), source, + config, timeType); } catch (IllegalArgumentException e) { throw new ConnectionRoutingException(e); } diff --git a/src/test/java/ch/naviqore/app/controller/DummyService.java b/src/test/java/ch/naviqore/app/controller/DummyService.java index 6d4b54e2..bf72db91 100644 --- a/src/test/java/ch/naviqore/app/controller/DummyService.java +++ b/src/test/java/ch/naviqore/app/controller/DummyService.java @@ -40,6 +40,11 @@ class DummyService implements PublicTransitService { List.of(STOP_D, STOP_E, STOP_F, STOP_G, STOP_H)); static final List ROUTES = List.of(ROUTE_1, ROUTE_2, ROUTE_3); + private boolean supportsMaxWalkingDuration; + private boolean supportsMinTransferDuration; + private boolean supportsMaxTransferNumber; + private boolean supportsMaxTravelTime; + private boolean hasAccessibilityInformation; private boolean hasBikeInformation; private boolean hasTravelModeInformation; @@ -69,6 +74,13 @@ public boolean isWithin(LocalDate date) { }; } + @Override + public SupportedRoutingFeatures getSupportedRoutingFeatures() { + return new SupportedRoutingFeatures(supportsMaxTransferNumber, supportsMaxTravelTime, + supportsMaxWalkingDuration, supportsMinTransferDuration, hasAccessibilityInformation, + hasBikeInformation, hasTravelModeInformation); + } + @Override public boolean hasAccessibilityInformation() { return hasAccessibilityInformation; From 8ec5d2dc78f83b392dcac59f6202318e54df56ea Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Thu, 22 Aug 2024 15:58:13 +0200 Subject: [PATCH 33/51] REFACTOR: NAV-131 - Rename info booleans in schedule info. --- src/main/java/ch/naviqore/app/dto/ScheduleInfo.java | 10 +++++++--- .../app/controller/ScheduleControllerTest.java | 6 +++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/java/ch/naviqore/app/dto/ScheduleInfo.java b/src/main/java/ch/naviqore/app/dto/ScheduleInfo.java index 365d035d..337d0563 100644 --- a/src/main/java/ch/naviqore/app/dto/ScheduleInfo.java +++ b/src/main/java/ch/naviqore/app/dto/ScheduleInfo.java @@ -3,13 +3,17 @@ import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.ToString; +import lombok.experimental.Accessors; @RequiredArgsConstructor @ToString @Getter public class ScheduleInfo { - final boolean supportsAccessibility; - final boolean supportsBikes; - final boolean supportsTravelModes; + @Accessors(fluent = true) + final boolean hasAccessibility; + @Accessors(fluent = true) + final boolean hasBikes; + @Accessors(fluent = true) + final boolean hasTravelModes; final ScheduleValidity scheduleValidity; } diff --git a/src/test/java/ch/naviqore/app/controller/ScheduleControllerTest.java b/src/test/java/ch/naviqore/app/controller/ScheduleControllerTest.java index 1455bbd8..1784d406 100644 --- a/src/test/java/ch/naviqore/app/controller/ScheduleControllerTest.java +++ b/src/test/java/ch/naviqore/app/controller/ScheduleControllerTest.java @@ -78,9 +78,9 @@ void testQueryConfigValues(boolean supportsAccessibility, boolean supportsBikes, ScheduleController scheduleController = new ScheduleController(dummyService); ch.naviqore.app.dto.ScheduleInfo routerInfo = scheduleController.getScheduleInfo(); - assertEquals(supportsAccessibility, routerInfo.isSupportsAccessibility()); - assertEquals(supportsBikes, routerInfo.isSupportsBikes()); - assertEquals(supportsTravelModes, routerInfo.isSupportsTravelModes()); + assertEquals(supportsAccessibility, routerInfo.hasAccessibility()); + assertEquals(supportsBikes, routerInfo.hasBikes()); + assertEquals(supportsTravelModes, routerInfo.hasTravelModes()); assertEquals(expStartDate, routerInfo.getScheduleValidity().getStartDate()); assertEquals(expEndDate, routerInfo.getScheduleValidity().getEndDate()); } From cf7114638d17f61cf60dccadec7b0ea44d2160ed Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Thu, 22 Aug 2024 16:02:14 +0200 Subject: [PATCH 34/51] ENH: NAV-131 - Add API endpoint for RoutingInfo --- .../app/controller/RoutingController.java | 16 ++++++++++++---- .../java/ch/naviqore/app/dto/RoutingInfo.java | 17 +++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 src/main/java/ch/naviqore/app/dto/RoutingInfo.java diff --git a/src/main/java/ch/naviqore/app/controller/RoutingController.java b/src/main/java/ch/naviqore/app/controller/RoutingController.java index 5244b1ee..217b759f 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingController.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingController.java @@ -1,12 +1,10 @@ package ch.naviqore.app.controller; import ch.naviqore.app.dto.Connection; +import ch.naviqore.app.dto.RoutingInfo; import ch.naviqore.app.dto.StopConnection; import ch.naviqore.app.dto.TimeType; -import ch.naviqore.service.PublicTransitService; -import ch.naviqore.service.ScheduleInformationService; -import ch.naviqore.service.Stop; -import ch.naviqore.service.TravelMode; +import ch.naviqore.service.*; import ch.naviqore.service.config.ConnectionQueryConfig; import ch.naviqore.service.exception.ConnectionRoutingException; import ch.naviqore.utils.spatial.GeoCoordinate; @@ -49,6 +47,16 @@ private static void handleConnectionRoutingException(ConnectionRoutingException throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()); } + @Operation(summary = "Get information about the routing", description = "Get all relevant information about the routing features supported by the service.") + @ApiResponse(responseCode = "200", description = "A list of routing features supported by the service.") + @GetMapping("/") + public RoutingInfo getRoutingInfo() { + SupportedRoutingFeatures features = service.getSupportedRoutingFeatures(); + return new RoutingInfo(features.supportsMaxNumTransfers(), features.supportsMaxTravelTime(), + features.supportsMaxWalkingTime(), features.supportsMinTransferTime(), features.supportsWheelchair(), + features.supportsBike(), features.supportsTravelMode()); + } + @Operation(summary = "Request connections between two stops or locations", description = "Requests connections between two stops or locations at a given departure / arrival datetime.") @ApiResponse(responseCode = "200", description = "A list of connections between the specified stops.") @ApiResponse(responseCode = "400", description = "Invalid input parameters", content = @Content(schema = @Schema())) diff --git a/src/main/java/ch/naviqore/app/dto/RoutingInfo.java b/src/main/java/ch/naviqore/app/dto/RoutingInfo.java new file mode 100644 index 00000000..2465e60c --- /dev/null +++ b/src/main/java/ch/naviqore/app/dto/RoutingInfo.java @@ -0,0 +1,17 @@ +package ch.naviqore.app.dto; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +@RequiredArgsConstructor +@ToString +@Getter +public class RoutingInfo { + final boolean supportsMaxNumTransfers; + final boolean supportsMaxTravelTime; + final boolean supportsMaxWalkingTime; + final boolean supportsMinTransferTime; + final boolean supportsAccessibility; + final boolean supportsBikes; + final boolean supportsTravelModes; +} From ee20632212e305517ca733fd030bc9aa7581019f Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Thu, 22 Aug 2024 16:26:04 +0200 Subject: [PATCH 35/51] REFACTOR: NAV-131 - Ensure Router Info variables are consistently named. --- .../app/controller/RoutingController.java | 4 ++-- .../java/ch/naviqore/app/dto/RoutingInfo.java | 6 ++++-- .../service/SupportedRoutingFeatures.java | 21 ++++++++++--------- .../gtfs/raptor/GtfsRaptorService.java | 2 +- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/main/java/ch/naviqore/app/controller/RoutingController.java b/src/main/java/ch/naviqore/app/controller/RoutingController.java index 217b759f..46b2fd04 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingController.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingController.java @@ -53,8 +53,8 @@ private static void handleConnectionRoutingException(ConnectionRoutingException public RoutingInfo getRoutingInfo() { SupportedRoutingFeatures features = service.getSupportedRoutingFeatures(); return new RoutingInfo(features.supportsMaxNumTransfers(), features.supportsMaxTravelTime(), - features.supportsMaxWalkingTime(), features.supportsMinTransferTime(), features.supportsWheelchair(), - features.supportsBike(), features.supportsTravelMode()); + features.supportsMaxWalkingDuration(), features.supportsMinTransferDuration(), features.supportsAccessibility(), + features.supportsBikes(), features.supportsTravelModes()); } @Operation(summary = "Request connections between two stops or locations", description = "Requests connections between two stops or locations at a given departure / arrival datetime.") diff --git a/src/main/java/ch/naviqore/app/dto/RoutingInfo.java b/src/main/java/ch/naviqore/app/dto/RoutingInfo.java index 2465e60c..b9ceaacf 100644 --- a/src/main/java/ch/naviqore/app/dto/RoutingInfo.java +++ b/src/main/java/ch/naviqore/app/dto/RoutingInfo.java @@ -2,15 +2,17 @@ import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.ToString; +import lombok.experimental.Accessors; @RequiredArgsConstructor @ToString @Getter +@Accessors(fluent = true) public class RoutingInfo { final boolean supportsMaxNumTransfers; final boolean supportsMaxTravelTime; - final boolean supportsMaxWalkingTime; - final boolean supportsMinTransferTime; + final boolean supportsMaxWalkingDuration; + final boolean supportsMinTransferDuration; final boolean supportsAccessibility; final boolean supportsBikes; final boolean supportsTravelModes; diff --git a/src/main/java/ch/naviqore/service/SupportedRoutingFeatures.java b/src/main/java/ch/naviqore/service/SupportedRoutingFeatures.java index 24b93438..7b6bf3b4 100644 --- a/src/main/java/ch/naviqore/service/SupportedRoutingFeatures.java +++ b/src/main/java/ch/naviqore/service/SupportedRoutingFeatures.java @@ -3,16 +3,17 @@ /** * Supported routing features of the service. * - * @param supportsMaxNumTransfers whether the service supports routing with a defined max number of transfers - * @param supportsMaxTravelTime whether the service supports routing with a defined max travel time (including waiting - * time) - * @param supportsMaxWalkingTime whether the service supports routing with a defined max walking time - * @param supportsMinTransferTime whether the service supports routing with a defined min transfer time - * @param supportsWheelchair whether the service supports routing for wheelchair users - * @param supportsBike whether the service supports routing for bike users - * @param supportsTravelMode whether the service supports routing for different travel modes + * @param supportsMaxNumTransfers whether the service supports routing with a defined max number of transfers + * @param supportsMaxTravelTime whether the service supports routing with a defined max travel time (including + * waiting time) + * @param supportsMaxWalkingDuration whether the service supports routing with a defined max walking time + * @param supportsMinTransferDuration whether the service supports routing with a defined min transfer time + * @param supportsAccessibility whether the service supports routing for wheelchair users + * @param supportsBikes whether the service supports routing for bike users + * @param supportsTravelModes whether the service supports routing for different travel modes */ public record SupportedRoutingFeatures(boolean supportsMaxNumTransfers, boolean supportsMaxTravelTime, - boolean supportsMaxWalkingTime, boolean supportsMinTransferTime, - boolean supportsWheelchair, boolean supportsBike, boolean supportsTravelMode) { + boolean supportsMaxWalkingDuration, boolean supportsMinTransferDuration, + boolean supportsAccessibility, boolean supportsBikes, + boolean supportsTravelModes) { } diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java b/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java index 0b8895c0..b998a556 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java @@ -156,7 +156,7 @@ public List getConnections(Stop source, Stop target, LocalDateTime t @Override public SupportedRoutingFeatures getSupportedRoutingFeatures() { return new SupportedRoutingFeatures(true, true, true, true, schedule.hasTripAccessibilityInformation(), - schedule.hasTripBikeInformation(), true ); + schedule.hasTripBikeInformation(), true); } @Override From 99976df05e2066c03f5ee97607c992444b41662a Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Thu, 22 Aug 2024 16:26:28 +0200 Subject: [PATCH 36/51] ENH: NAV-131 - Extend Routing Controller test. --- .../app/controller/RoutingControllerTest.java | 47 ++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java index 0e3fcc30..66bc4d7a 100644 --- a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java +++ b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java @@ -12,8 +12,10 @@ import org.springframework.web.server.ResponseStatusException; import java.time.LocalDateTime; +import java.util.Arrays; import java.util.EnumSet; import java.util.List; +import java.util.stream.Collectors; import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.*; @@ -569,7 +571,50 @@ void testQueryConfigValues(String name, Integer maxWalkingDuration, Integer maxT } @Nested - class RouterInfoEndpoint { + class RoutingInfo { + static Stream provideRoutingInfoTestCombinations() { + List combinations = generateBooleanCombinations(7); + return combinations.stream() + .map(arr -> Arguments.of(arr[0], arr[1], arr[2], arr[3], arr[4], arr[5], arr[6])); + } + + private static List generateBooleanCombinations(int length) { + return Stream.iterate(new boolean[length], arr -> { + boolean[] next = Arrays.copyOf(arr, length); + for (int i = length - 1; i >= 0; i--) { + if (next[i]) { + next[i] = false; + } else { + next[i] = true; + break; + } + } + return next; + }).limit((long) Math.pow(2, length)).collect(Collectors.toList()); + } + @ParameterizedTest(name = "maxNumTransfers_{0}_maxTravelTime_{1}_maxWalkingTime_{2}_minTransferTime_{3}_accessibility_{4}_bikes_{5}_travelModes_{6}") + @MethodSource("provideRoutingInfoTestCombinations") + void testQueryConfigValues(boolean supportsMaxNumTransfers, boolean supportsMaxTravelTime, + boolean supportsMaxWalkingDuration, boolean supportsMinTransferDuration, + boolean supportsAccessibility, boolean supportsBikes, boolean supportsTravelModes) { + dummyService.setHasAccessibilityInformation(supportsAccessibility); + dummyService.setHasBikeInformation(supportsBikes); + dummyService.setHasTravelModeInformation(supportsTravelModes); + dummyService.setSupportsMaxTransferNumber(supportsMaxNumTransfers); + dummyService.setSupportsMaxTravelTime(supportsMaxTravelTime); + dummyService.setSupportsMaxWalkingDuration(supportsMaxWalkingDuration); + dummyService.setSupportsMinTransferDuration(supportsMinTransferDuration); + + ch.naviqore.app.dto.RoutingInfo routingInfo = routingController.getRoutingInfo(); + + assertEquals(supportsAccessibility, routingInfo.supportsAccessibility()); + assertEquals(supportsBikes, routingInfo.supportsBikes()); + assertEquals(supportsTravelModes, routingInfo.supportsTravelModes()); + assertEquals(supportsMaxNumTransfers, routingInfo.supportsMaxNumTransfers()); + assertEquals(supportsMaxTravelTime, routingInfo.supportsMaxTravelTime()); + assertEquals(supportsMaxWalkingDuration, routingInfo.supportsMaxWalkingDuration()); + assertEquals(supportsMinTransferDuration, routingInfo.supportsMinTransferDuration()); + } } } From 10c58c6fb85fb65412ee8143dfca4bebcbddbe0c Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Thu, 22 Aug 2024 17:49:02 +0200 Subject: [PATCH 37/51] REFACTROR: NAV-131 - Remove accessors(fluent=true) in DTOs (does not work). --- src/main/java/ch/naviqore/app/dto/RoutingInfo.java | 2 -- .../java/ch/naviqore/app/dto/ScheduleInfo.java | 4 ---- .../app/controller/RoutingControllerTest.java | 14 +++++++------- .../app/controller/ScheduleControllerTest.java | 6 +++--- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/main/java/ch/naviqore/app/dto/RoutingInfo.java b/src/main/java/ch/naviqore/app/dto/RoutingInfo.java index b9ceaacf..b3304322 100644 --- a/src/main/java/ch/naviqore/app/dto/RoutingInfo.java +++ b/src/main/java/ch/naviqore/app/dto/RoutingInfo.java @@ -2,12 +2,10 @@ import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.ToString; -import lombok.experimental.Accessors; @RequiredArgsConstructor @ToString @Getter -@Accessors(fluent = true) public class RoutingInfo { final boolean supportsMaxNumTransfers; final boolean supportsMaxTravelTime; diff --git a/src/main/java/ch/naviqore/app/dto/ScheduleInfo.java b/src/main/java/ch/naviqore/app/dto/ScheduleInfo.java index 337d0563..33edb167 100644 --- a/src/main/java/ch/naviqore/app/dto/ScheduleInfo.java +++ b/src/main/java/ch/naviqore/app/dto/ScheduleInfo.java @@ -3,17 +3,13 @@ import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.ToString; -import lombok.experimental.Accessors; @RequiredArgsConstructor @ToString @Getter public class ScheduleInfo { - @Accessors(fluent = true) final boolean hasAccessibility; - @Accessors(fluent = true) final boolean hasBikes; - @Accessors(fluent = true) final boolean hasTravelModes; final ScheduleValidity scheduleValidity; } diff --git a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java index 66bc4d7a..b96d5f72 100644 --- a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java +++ b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java @@ -608,13 +608,13 @@ void testQueryConfigValues(boolean supportsMaxNumTransfers, boolean supportsMaxT ch.naviqore.app.dto.RoutingInfo routingInfo = routingController.getRoutingInfo(); - assertEquals(supportsAccessibility, routingInfo.supportsAccessibility()); - assertEquals(supportsBikes, routingInfo.supportsBikes()); - assertEquals(supportsTravelModes, routingInfo.supportsTravelModes()); - assertEquals(supportsMaxNumTransfers, routingInfo.supportsMaxNumTransfers()); - assertEquals(supportsMaxTravelTime, routingInfo.supportsMaxTravelTime()); - assertEquals(supportsMaxWalkingDuration, routingInfo.supportsMaxWalkingDuration()); - assertEquals(supportsMinTransferDuration, routingInfo.supportsMinTransferDuration()); + assertEquals(supportsAccessibility, routingInfo.isSupportsAccessibility()); + assertEquals(supportsBikes, routingInfo.isSupportsBikes()); + assertEquals(supportsTravelModes, routingInfo.isSupportsTravelModes()); + assertEquals(supportsMaxNumTransfers, routingInfo.isSupportsMaxNumTransfers()); + assertEquals(supportsMaxTravelTime, routingInfo.isSupportsMaxTravelTime()); + assertEquals(supportsMaxWalkingDuration, routingInfo.isSupportsMaxWalkingDuration()); + assertEquals(supportsMinTransferDuration, routingInfo.isSupportsMinTransferDuration()); } } } diff --git a/src/test/java/ch/naviqore/app/controller/ScheduleControllerTest.java b/src/test/java/ch/naviqore/app/controller/ScheduleControllerTest.java index 1784d406..bc23e721 100644 --- a/src/test/java/ch/naviqore/app/controller/ScheduleControllerTest.java +++ b/src/test/java/ch/naviqore/app/controller/ScheduleControllerTest.java @@ -78,9 +78,9 @@ void testQueryConfigValues(boolean supportsAccessibility, boolean supportsBikes, ScheduleController scheduleController = new ScheduleController(dummyService); ch.naviqore.app.dto.ScheduleInfo routerInfo = scheduleController.getScheduleInfo(); - assertEquals(supportsAccessibility, routerInfo.hasAccessibility()); - assertEquals(supportsBikes, routerInfo.hasBikes()); - assertEquals(supportsTravelModes, routerInfo.hasTravelModes()); + assertEquals(supportsAccessibility, routerInfo.isHasAccessibility()); + assertEquals(supportsBikes, routerInfo.isHasBikes()); + assertEquals(supportsTravelModes, routerInfo.isHasTravelModes()); assertEquals(expStartDate, routerInfo.getScheduleValidity().getStartDate()); assertEquals(expEndDate, routerInfo.getScheduleValidity().getEndDate()); } From 9e97b4f64ab24e138ab2e5b16e71c1937d4ddec8 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Thu, 22 Aug 2024 18:48:42 +0200 Subject: [PATCH 38/51] ENH: NAV-131 - Add better validation based on routing capabilities in router controller. --- .../controller/RoutingRequestValidator.java | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java b/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java index adda7883..d3dc520b 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java @@ -42,20 +42,37 @@ public static void validateQueryParams(int maxWalkingDuration, int maxTransferNu "Min transfer time must be greater than or equal to 0."); } - // If the service does not support accessibility information, bike information, or travel mode information, - // only default values are allowed (i.e., false for wheelchairAccessible, false for bikeAllowed, - // and all travel modes). - if (wheelchairAccessible && !service.hasAccessibilityInformation()) { + // check support of routing features + if (maxWalkingDuration != Integer.MAX_VALUE && !service.getSupportedRoutingFeatures() + .supportsMaxWalkingDuration()) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, - "Accessibility information is not available for this service."); + "Max Walking Duration is not supported by the router of this service."); } - if (bikeAllowed && !service.hasBikeInformation()) { + if (maxTransferNumber != Integer.MAX_VALUE && !service.getSupportedRoutingFeatures() + .supportsMaxNumTransfers()) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, - "Bike information is not available for this service."); + "Max Transfer Number is not supported by the router of this service."); } - if (!travelModes.containsAll(EnumSet.allOf(TravelMode.class)) && !service.hasTravelModeInformation()) { + if (maxTravelTime != Integer.MAX_VALUE && !service.getSupportedRoutingFeatures().supportsMaxTravelTime()) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, - "Service does not support travel mode information."); + "Max Travel Time is not supported by the router of this service."); + } + if (minTransferTime != 0 && !service.getSupportedRoutingFeatures().supportsMinTransferDuration()) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, + "Min Transfer Duration is not supported by the router of this service."); + } + if (wheelchairAccessible && !service.getSupportedRoutingFeatures().supportsAccessibility()) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, + "Wheelchair Accessible routing is not supported by the router of this service."); + } + if (bikeAllowed && !service.getSupportedRoutingFeatures().supportsBikes()) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, + "Bike friendly routing is not supported by the router of this service."); + } + if (!travelModes.containsAll(EnumSet.allOf(TravelMode.class)) && !service.getSupportedRoutingFeatures() + .supportsAccessibility()) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, + "Filtering travel modes is not supported by the router of this service."); } } From 19c55ee69006cab24afa9320efde7ee5a70ed617 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Thu, 22 Aug 2024 19:22:58 +0200 Subject: [PATCH 39/51] TEST: NAV-141 - Add test case for routing request when target and source coordinates are identical. --- .../app/controller/RoutingControllerTest.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java index b96d5f72..c62d264a 100644 --- a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java +++ b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java @@ -190,6 +190,21 @@ void testRoutingBetweenSameStops() { assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); } + @Test + void testRoutingBetweenSameCoordinates() { + // Arrange + double latitude = 46.2044; + double longitude = 6.1432; + LocalDateTime departureDateTime = LocalDateTime.now(); + // Act & Assert + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> getConnections(null, latitude, longitude, null, latitude, longitude, departureDateTime)); + assertEquals( + "The source and target coordinates cannot be the same. Please provide different coordinates for the source and target.", + exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + @Test void testMissingSourceStopAndSourceCoordinates() { // Act & Assert From 9f4bd0d898520581d5e9de72be2d7f633df09af3 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Thu, 22 Aug 2024 19:26:15 +0200 Subject: [PATCH 40/51] ENH: NAV-141 - Include check if source and target coordinates are identical. --- .../java/ch/naviqore/app/controller/RoutingController.java | 1 + .../naviqore/app/controller/RoutingRequestValidator.java | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/src/main/java/ch/naviqore/app/controller/RoutingController.java b/src/main/java/ch/naviqore/app/controller/RoutingController.java index 46b2fd04..4ba0573f 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingController.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingController.java @@ -102,6 +102,7 @@ public List getConnections(@RequestParam(required = false) String so } else if (targetStop != null) { return map(service.getConnections(sourceCoordinate, targetStop, dateTime, map(timeType), config)); } else { + RoutingRequestValidator.validateCoordinates(sourceCoordinate, targetCoordinate); return map(service.getConnections(sourceCoordinate, targetCoordinate, dateTime, map(timeType), config)); } } catch (ConnectionRoutingException e) { diff --git a/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java b/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java index d3dc520b..6ff2da2e 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java @@ -100,4 +100,11 @@ public static void validateStops(String sourceStopId, String targetStopId) { } } + public static void validateCoordinates(GeoCoordinate sourceCoordinate, GeoCoordinate targetCoordinate) { + if (sourceCoordinate.equals(targetCoordinate)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, + "The source and target coordinates cannot be the same. Please provide different coordinates for the source and target."); + } + } + } From 330250306175fbe9bd7b632f70953a21b51a38b0 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Thu, 22 Aug 2024 19:35:03 +0200 Subject: [PATCH 41/51] TEST: NAV-141 - Fix failing test because test case had same source and target coordinates. --- .../ch/naviqore/app/controller/RoutingControllerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java index c62d264a..35e2c9bf 100644 --- a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java +++ b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java @@ -268,12 +268,12 @@ void testQueryConfigValues(String name, Integer maxWalkingDuration, Integer maxT dummyService.setHasTravelModeInformation(hasTravelModeInformation); if (errorMessage == null) { - routingController.getConnections(null, 0., 0., null, 0., 0., LocalDateTime.now(), TimeType.DEPARTURE, + routingController.getConnections(null, 0., 0., null, 1., 1., LocalDateTime.now(), TimeType.DEPARTURE, maxWalkingDuration, maxTransferDuration, maxTravelTime, minTransferTime, wheelChairAccessible, bikeAllowed, travelModes); } else { ResponseStatusException exception = assertThrows(ResponseStatusException.class, - () -> routingController.getConnections(null, 0., 0., null, 0., 0., LocalDateTime.now(), + () -> routingController.getConnections(null, 0., 0., null, 1., 1., LocalDateTime.now(), TimeType.DEPARTURE, maxWalkingDuration, maxTransferDuration, maxTravelTime, minTransferTime, wheelChairAccessible, bikeAllowed, travelModes)); assertEquals(errorMessage, exception.getReason()); From 4770d29cdcd7d00c4cb13ffbdb11c4594a6de0f5 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Thu, 22 Aug 2024 19:38:45 +0200 Subject: [PATCH 42/51] TEST: NAV-131 - Update expected error messages in tests --- .../ch/naviqore/app/controller/RoutingControllerTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java index 35e2c9bf..e1413784 100644 --- a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java +++ b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java @@ -71,15 +71,15 @@ static Stream provideQueryConfigTestCombinations() { Arguments.of("wheelchairAccessibleWhenServiceProvidesNoSupport", validMaxWalkingDuration, validMaxTransferDuration, validMaxTravelTime, validMinTransferTime, true, validBikeAllowed, validTravelModes, false, hasBikeInformation, hasTravelModeInformation, - "Accessibility information is not available for this service."), + "Wheelchair Accessible routing is not supported by the router of this service."), Arguments.of("bikeAllowedWhenServiceProvidesNoSupport", validMaxWalkingDuration, validMaxTransferDuration, validMaxTravelTime, validMinTransferTime, validWheelChairAccessible, true, validTravelModes, hasAccessibilityInformation, false, hasTravelModeInformation, - "Bike information is not available for this service."), + "Bike friendly routing is not supported by the router of this service."), Arguments.of("travelModesWhenServiceProvidesNoSupport", validMaxWalkingDuration, validMaxTransferDuration, validMaxTravelTime, validMinTransferTime, validWheelChairAccessible, validBikeAllowed, EnumSet.of(TravelMode.BUS), hasAccessibilityInformation, hasBikeInformation, - false, "Service does not support travel mode information."), + false, "Filtering travel modes is not supported by the router of this service."), Arguments.of("wheelchairAccessibleWhenServiceProvidesSupport", validMaxWalkingDuration, validMaxTransferDuration, validMaxTravelTime, validMinTransferTime, true, validBikeAllowed, validTravelModes, hasAccessibilityInformation, hasBikeInformation, hasTravelModeInformation, From 748a5318764e3ab082061ede12fb54adfab143f3 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Thu, 22 Aug 2024 19:39:33 +0200 Subject: [PATCH 43/51] TEST: NAV-131 - Add appropriate default values for routing features in dummy service. --- .../ch/naviqore/app/controller/DummyService.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/java/ch/naviqore/app/controller/DummyService.java b/src/test/java/ch/naviqore/app/controller/DummyService.java index bf72db91..fd821867 100644 --- a/src/test/java/ch/naviqore/app/controller/DummyService.java +++ b/src/test/java/ch/naviqore/app/controller/DummyService.java @@ -40,14 +40,14 @@ class DummyService implements PublicTransitService { List.of(STOP_D, STOP_E, STOP_F, STOP_G, STOP_H)); static final List ROUTES = List.of(ROUTE_1, ROUTE_2, ROUTE_3); - private boolean supportsMaxWalkingDuration; - private boolean supportsMinTransferDuration; - private boolean supportsMaxTransferNumber; - private boolean supportsMaxTravelTime; - - private boolean hasAccessibilityInformation; - private boolean hasBikeInformation; - private boolean hasTravelModeInformation; + private boolean supportsMaxWalkingDuration = true; + private boolean supportsMinTransferDuration = true; + private boolean supportsMaxTransferNumber = true; + private boolean supportsMaxTravelTime = true; + + private boolean hasAccessibilityInformation = false; + private boolean hasBikeInformation = false; + private boolean hasTravelModeInformation = false; @Override public Validity getValidity() { From 84c061404e94073b47489b83142a0915010bc3b3 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Thu, 22 Aug 2024 19:42:23 +0200 Subject: [PATCH 44/51] FIX: NAV-131 - Fix logical error in checking if travel mode routing is available. --- .../ch/naviqore/app/controller/RoutingRequestValidator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java b/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java index 6ff2da2e..0c6b3a31 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java @@ -70,7 +70,7 @@ public static void validateQueryParams(int maxWalkingDuration, int maxTransferNu "Bike friendly routing is not supported by the router of this service."); } if (!travelModes.containsAll(EnumSet.allOf(TravelMode.class)) && !service.getSupportedRoutingFeatures() - .supportsAccessibility()) { + .supportsTravelModes()) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Filtering travel modes is not supported by the router of this service."); } From 8db6d76f79fa67c3d986b72b275bf981374d4d57 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Thu, 22 Aug 2024 20:56:00 +0200 Subject: [PATCH 45/51] ENH: NAV-131 - Add TravelMode Enum as DTO. --- .../app/controller/RoutingController.java | 4 +-- .../java/ch/naviqore/app/dto/DtoMapper.java | 25 ++++++++++++++----- .../java/ch/naviqore/app/dto/TravelMode.java | 11 ++++++++ .../app/controller/RoutingControllerTest.java | 1 - 4 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 src/main/java/ch/naviqore/app/dto/TravelMode.java diff --git a/src/main/java/ch/naviqore/app/controller/RoutingController.java b/src/main/java/ch/naviqore/app/controller/RoutingController.java index 4ba0573f..a20668a7 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingController.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingController.java @@ -4,6 +4,7 @@ import ch.naviqore.app.dto.RoutingInfo; import ch.naviqore.app.dto.StopConnection; import ch.naviqore.app.dto.TimeType; +import ch.naviqore.app.dto.TravelMode; import ch.naviqore.service.*; import ch.naviqore.service.config.ConnectionQueryConfig; import ch.naviqore.service.exception.ConnectionRoutingException; @@ -91,7 +92,6 @@ public List getConnections(@RequestParam(required = false) String so dateTime = GlobalValidator.validateAndSetDefaultDateTime(dateTime, service); ConnectionQueryConfig config = Utils.createConfig(maxWalkingDuration, maxTransferNumber, maxTravelTime, minTransferTime, wheelchairAccessible, bikeAllowed, travelModes, service); - // determine routing case and get connections try { if (sourceStop != null && targetStop != null) { @@ -190,7 +190,7 @@ private static ConnectionQueryConfig createConfig(@Nullable Integer maxWalkingDu RoutingRequestValidator.validateQueryParams(maxWalkingDuration, maxTransferNumber, maxTravelTime, minTransferTime, wheelchairAccessible, bikeAllowed, travelModes, service); return new ConnectionQueryConfig(maxWalkingDuration, minTransferTime, maxTransferNumber, maxTravelTime, - wheelchairAccessible, bikeAllowed, travelModes); + wheelchairAccessible, bikeAllowed, map(travelModes)); } private static int setToMaxIfNull(Integer value) { diff --git a/src/main/java/ch/naviqore/app/dto/DtoMapper.java b/src/main/java/ch/naviqore/app/dto/DtoMapper.java index 5ebcf603..989cac3f 100644 --- a/src/main/java/ch/naviqore/app/dto/DtoMapper.java +++ b/src/main/java/ch/naviqore/app/dto/DtoMapper.java @@ -6,6 +6,7 @@ import lombok.NoArgsConstructor; import java.util.ArrayList; +import java.util.EnumSet; import java.util.List; import java.util.Map; @@ -40,13 +41,25 @@ public static Route map(ch.naviqore.service.Route route) { return new Route(route.getId(), route.getName(), route.getShortName(), route.getRouteType()); } + public static TravelMode map(ch.naviqore.service.TravelMode travelMode) { + return TravelMode.valueOf(travelMode.name()); + } + + public static ch.naviqore.service.TravelMode map(TravelMode travelMode) { + return ch.naviqore.service.TravelMode.valueOf(travelMode.name()); + } + + public static EnumSet map(EnumSet travelModes) { + EnumSet serviceTravelModes = EnumSet.noneOf( + ch.naviqore.service.TravelMode.class); + for (TravelMode travelMode : travelModes) { + serviceTravelModes.add(map(travelMode)); + } + return serviceTravelModes; + } + public static SearchType map(ch.naviqore.app.dto.SearchType searchType) { - return switch (searchType) { - case STARTS_WITH -> SearchType.STARTS_WITH; - case ENDS_WITH -> SearchType.ENDS_WITH; - case CONTAINS -> SearchType.CONTAINS; - case EXACT -> SearchType.EXACT; - }; + return SearchType.valueOf(searchType.name()); } public static ch.naviqore.service.TimeType map(TimeType timeType) { diff --git a/src/main/java/ch/naviqore/app/dto/TravelMode.java b/src/main/java/ch/naviqore/app/dto/TravelMode.java new file mode 100644 index 00000000..888de31c --- /dev/null +++ b/src/main/java/ch/naviqore/app/dto/TravelMode.java @@ -0,0 +1,11 @@ +package ch.naviqore.app.dto; + +public enum TravelMode { + BUS, + TRAM, + RAIL, + SHIP, + SUBWAY, + AERIAL_LIFT, + FUNICULAR, +} diff --git a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java index e1413784..f3f6caa0 100644 --- a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java +++ b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java @@ -1,7 +1,6 @@ package ch.naviqore.app.controller; import ch.naviqore.app.dto.*; -import ch.naviqore.service.TravelMode; import ch.naviqore.utils.spatial.GeoCoordinate; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; From c98b1d098280cbd4e150c7bdfebe616a045246cb Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Thu, 22 Aug 2024 20:56:58 +0200 Subject: [PATCH 46/51] ENH: NAV-148 - Add TravelMode to Route DTO in App and Accessibility and BikeInfo to Trip DTO. --- .../controller/RoutingRequestValidator.java | 2 +- .../java/ch/naviqore/app/dto/DtoMapper.java | 6 ++-- src/main/java/ch/naviqore/app/dto/Route.java | 3 +- .../ch/naviqore/app/dto/StopConnection.java | 3 +- src/main/java/ch/naviqore/app/dto/Trip.java | 2 ++ src/main/java/ch/naviqore/service/Route.java | 4 ++- src/main/java/ch/naviqore/service/Trip.java | 4 +++ .../service/gtfs/raptor/GtfsRaptorRoute.java | 4 ++- .../service/gtfs/raptor/GtfsRaptorTrip.java | 2 ++ .../service/gtfs/raptor/TypeMapper.java | 33 +++++++++++++++++-- .../naviqore/app/controller/DummyService.java | 8 ++--- .../app/controller/DummyServiceModels.java | 6 +++- 12 files changed, 63 insertions(+), 14 deletions(-) diff --git a/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java b/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java index 0c6b3a31..505ddf35 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java @@ -1,7 +1,7 @@ package ch.naviqore.app.controller; +import ch.naviqore.app.dto.TravelMode; import ch.naviqore.service.PublicTransitService; -import ch.naviqore.service.TravelMode; import ch.naviqore.utils.spatial.GeoCoordinate; import lombok.AccessLevel; import lombok.NoArgsConstructor; diff --git a/src/main/java/ch/naviqore/app/dto/DtoMapper.java b/src/main/java/ch/naviqore/app/dto/DtoMapper.java index 989cac3f..3558af8d 100644 --- a/src/main/java/ch/naviqore/app/dto/DtoMapper.java +++ b/src/main/java/ch/naviqore/app/dto/DtoMapper.java @@ -34,11 +34,13 @@ public static Trip map(ch.naviqore.service.Trip trip) { stopTime.getDepartureTime())) .toList(); - return new Trip(trip.getHeadSign(), map(trip.getRoute()), stopTimes); + return new Trip(trip.getHeadSign(), map(trip.getRoute()), stopTimes, trip.isBikesAllowed(), + trip.isWheelchairAccessible()); } public static Route map(ch.naviqore.service.Route route) { - return new Route(route.getId(), route.getName(), route.getShortName(), route.getRouteType()); + return new Route(route.getId(), route.getName(), route.getShortName(), map(route.getRouteType()), + route.getRouteTypeDescription()); } public static TravelMode map(ch.naviqore.service.TravelMode travelMode) { diff --git a/src/main/java/ch/naviqore/app/dto/Route.java b/src/main/java/ch/naviqore/app/dto/Route.java index 118cb0ce..b15b5075 100644 --- a/src/main/java/ch/naviqore/app/dto/Route.java +++ b/src/main/java/ch/naviqore/app/dto/Route.java @@ -11,7 +11,8 @@ public class Route { private final String id; private final String name; private final String shortName; - private final String transportMode; + private final TravelMode transportMode; + private final String transportModeDescription; } diff --git a/src/main/java/ch/naviqore/app/dto/StopConnection.java b/src/main/java/ch/naviqore/app/dto/StopConnection.java index 247e1bc6..6ee79b15 100644 --- a/src/main/java/ch/naviqore/app/dto/StopConnection.java +++ b/src/main/java/ch/naviqore/app/dto/StopConnection.java @@ -110,7 +110,8 @@ private void reduceData() { if (connectingLeg.getTrip() == null) { return; } - Trip reducedTrip = new Trip(connectingLeg.getTrip().getHeadSign(), connectingLeg.getTrip().getRoute(), null); + Trip reducedTrip = new Trip(connectingLeg.getTrip().getHeadSign(), connectingLeg.getTrip().getRoute(), null, + connectingLeg.getTrip().isBikesAllowed(), connectingLeg.getTrip().isWheelchairAccessible()); connectingLeg = new Leg(connectingLeg.getType(), connectingLeg.getFrom(), connectingLeg.getTo(), connectingLeg.getFromStop(), connectingLeg.getToStop(), connectingLeg.getDepartureTime(), connectingLeg.getArrivalTime(), reducedTrip); diff --git a/src/main/java/ch/naviqore/app/dto/Trip.java b/src/main/java/ch/naviqore/app/dto/Trip.java index e51eda25..d7f22c65 100644 --- a/src/main/java/ch/naviqore/app/dto/Trip.java +++ b/src/main/java/ch/naviqore/app/dto/Trip.java @@ -13,6 +13,8 @@ public class Trip { private final String headSign; private final Route route; private final List stopTimes; + private final boolean bikesAllowed; + private final boolean wheelchairAccessible; } diff --git a/src/main/java/ch/naviqore/service/Route.java b/src/main/java/ch/naviqore/service/Route.java index 9fcedb61..2409d114 100644 --- a/src/main/java/ch/naviqore/service/Route.java +++ b/src/main/java/ch/naviqore/service/Route.java @@ -11,7 +11,9 @@ public interface Route { String getShortName(); - String getRouteType(); + TravelMode getRouteType(); + + String getRouteTypeDescription(); String getAgency(); diff --git a/src/main/java/ch/naviqore/service/Trip.java b/src/main/java/ch/naviqore/service/Trip.java index 4d91bbdb..7943c169 100644 --- a/src/main/java/ch/naviqore/service/Trip.java +++ b/src/main/java/ch/naviqore/service/Trip.java @@ -17,4 +17,8 @@ public interface Trip { List getStopTimes(); + boolean isWheelchairAccessible(); + + boolean isBikesAllowed(); + } diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorRoute.java b/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorRoute.java index 0bae8170..b430ac3a 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorRoute.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorRoute.java @@ -1,6 +1,7 @@ package ch.naviqore.service.gtfs.raptor; import ch.naviqore.service.Route; +import ch.naviqore.service.TravelMode; import lombok.AccessLevel; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -14,7 +15,8 @@ public class GtfsRaptorRoute implements Route { private final String id; private final String name; private final String shortName; - private final String routeType; + private final TravelMode routeType; + private final String routeTypeDescription; private final String Agency; } diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorTrip.java b/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorTrip.java index 6ac0fff3..82312a1f 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorTrip.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorTrip.java @@ -19,5 +19,7 @@ public class GtfsRaptorTrip implements Trip { private final String headSign; private final Route route; private final List stopTimes; + private final boolean bikesAllowed; + private final boolean wheelchairAccessible; } diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/TypeMapper.java b/src/main/java/ch/naviqore/service/gtfs/raptor/TypeMapper.java index 481b8c37..9a8a2648 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/TypeMapper.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/TypeMapper.java @@ -1,6 +1,7 @@ package ch.naviqore.service.gtfs.raptor; import ch.naviqore.gtfs.schedule.model.GtfsSchedule; +import ch.naviqore.gtfs.schedule.type.*; import ch.naviqore.raptor.QueryConfig; import ch.naviqore.service.*; import ch.naviqore.service.config.ConnectionQueryConfig; @@ -32,7 +33,7 @@ public static Stop map(ch.naviqore.gtfs.schedule.model.Stop stop) { } public static Route map(ch.naviqore.gtfs.schedule.model.Route route) { - return new GtfsRaptorRoute(route.getId(), route.getLongName(), route.getShortName(), + return new GtfsRaptorRoute(route.getId(), route.getLongName(), route.getShortName(), map(route.getType()), route.getType().getDescription(), route.getAgency().name()); } @@ -46,7 +47,9 @@ public static Trip map(ch.naviqore.gtfs.schedule.model.Trip trip, LocalDate date // initialize trip, needs a cast to stop times from stop time impl (list) GtfsRaptorTrip gtfsRaptorTrip = new GtfsRaptorTrip(trip.getId(), trip.getHeadSign(), map(trip.getRoute()), - stopTimes.stream().map(stopTime -> (StopTime) stopTime).toList()); + stopTimes.stream().map(stopTime -> (StopTime) stopTime).toList(), + trip.getBikesAllowed() == BikeInformation.ALLOWED, + trip.getWheelchairAccessible() == AccessibilityInformation.ACCESSIBLE); // set trip on stop times impls stopTimes.forEach(stopTime -> stopTime.setTrip(gtfsRaptorTrip)); @@ -132,6 +135,32 @@ public static EnumSet map(EnumSet tra return raptorTravelModes; } + private static TravelMode map(RouteType routeType) { + DefaultRouteType defaultRouteType = RouteTypeMapper.map(routeType); + switch (defaultRouteType) { + case BUS: + case TROLLEYBUS: + return TravelMode.BUS; + case TRAM: + case CABLE_TRAM: + return TravelMode.TRAM; + case RAIL: + case MONORAIL: + return TravelMode.RAIL; + case FERRY: + return TravelMode.SHIP; + case SUBWAY: + return TravelMode.SUBWAY; + case AERIAL_LIFT: + return TravelMode.AERIAL_LIFT; + case FUNICULAR: + return TravelMode.FUNICULAR; + default: + // should never happen + throw new IllegalArgumentException("Route type not supported"); + } + } + private static Leg createPublicTransitLeg(ch.naviqore.raptor.Leg leg, GtfsSchedule schedule, int distance) { ch.naviqore.gtfs.schedule.model.Trip gtfsTrip = schedule.getTrips().get(leg.getTripId()); LocalDate serviceDay = getServiceDay(leg, gtfsTrip); diff --git a/src/test/java/ch/naviqore/app/controller/DummyService.java b/src/test/java/ch/naviqore/app/controller/DummyService.java index fd821867..96c65b33 100644 --- a/src/test/java/ch/naviqore/app/controller/DummyService.java +++ b/src/test/java/ch/naviqore/app/controller/DummyService.java @@ -30,13 +30,13 @@ class DummyService implements PublicTransitService { static final List STOPS = List.of(STOP_A, STOP_B, STOP_C, STOP_D, STOP_E, STOP_F, STOP_G, STOP_H); private static final RouteData ROUTE_1 = new RouteData( - new DummyServiceModels.Route("1", "Route 1", "R1", "BUS", "Agency 1"), + new DummyServiceModels.Route("1", "Route 1", "R1", TravelMode.BUS, "BUS", "Agency 1"), List.of(STOP_A, STOP_B, STOP_C, STOP_D, STOP_E, STOP_F, STOP_G)); private static final RouteData ROUTE_2 = new RouteData( - new DummyServiceModels.Route("2", "Route 2", "R2", "BUS", "Agency 2"), + new DummyServiceModels.Route("2", "Route 2", "R2", TravelMode.BUS, "BUS", "Agency 2"), List.of(STOP_A, STOP_B, STOP_C, STOP_D)); private static final RouteData ROUTE_3 = new RouteData( - new DummyServiceModels.Route("3", "Route 3", "R3", "BUS", "Agency 3"), + new DummyServiceModels.Route("3", "Route 3", "R3", TravelMode.BUS, "BUS", "Agency 3"), List.of(STOP_D, STOP_E, STOP_F, STOP_G, STOP_H)); static final List ROUTES = List.of(ROUTE_1, ROUTE_2, ROUTE_3); @@ -403,7 +403,7 @@ private static DummyServiceModels.PublicTransitLeg getPublicTransitLeg(RouteData int refIndex = timeType == TimeType.DEPARTURE ? startStopIndex : endStopIndex; DummyServiceModels.Trip trip = new DummyServiceModels.Trip(route.route().getId() + "_" + startStop.getId(), - "Head Sign", route.route()); + "Head Sign", route.route(), false, false); List stopTimes = new ArrayList<>(); for (int i = 0; i < route.stops().size(); i++) { DummyServiceModels.Stop stop = route.stops().get(i); diff --git a/src/test/java/ch/naviqore/app/controller/DummyServiceModels.java b/src/test/java/ch/naviqore/app/controller/DummyServiceModels.java index 818f5a32..ea64975c 100644 --- a/src/test/java/ch/naviqore/app/controller/DummyServiceModels.java +++ b/src/test/java/ch/naviqore/app/controller/DummyServiceModels.java @@ -2,6 +2,7 @@ import ch.naviqore.service.LegType; import ch.naviqore.service.LegVisitor; +import ch.naviqore.service.TravelMode; import ch.naviqore.service.WalkType; import ch.naviqore.utils.spatial.GeoCoordinate; import lombok.Getter; @@ -105,7 +106,8 @@ static class Route implements ch.naviqore.service.Route { private final String id; private final String name; private final String shortName; - private final String routeType; + private final TravelMode routeType; + private final String routeTypeDescription; private final String Agency; } @@ -116,6 +118,8 @@ static class Trip implements ch.naviqore.service.Trip { private final String id; private final String headSign; private final Route route; + private final boolean bikesAllowed; + private final boolean wheelchairAccessible; @Setter private List stopTimes; From 5bcbf529a51c50ec937dd6a8e4af024ce1ffc727 Mon Sep 17 00:00:00 2001 From: Merlin Unterfinger Date: Fri, 23 Aug 2024 09:10:54 +0200 Subject: [PATCH 47/51] STYLE: NAV-131 - Format project --- .../app/controller/RoutingController.java | 15 +++++++-------- .../java/ch/naviqore/app/dto/RoutingInfo.java | 3 +++ .../java/ch/naviqore/app/dto/ScheduleInfo.java | 2 ++ .../java/ch/naviqore/raptor/RaptorAlgorithm.java | 4 ---- .../raptor/convert/GtfsToRaptorConverter.java | 1 - 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/main/java/ch/naviqore/app/controller/RoutingController.java b/src/main/java/ch/naviqore/app/controller/RoutingController.java index a20668a7..095537f0 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingController.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingController.java @@ -1,11 +1,10 @@ package ch.naviqore.app.controller; -import ch.naviqore.app.dto.Connection; -import ch.naviqore.app.dto.RoutingInfo; -import ch.naviqore.app.dto.StopConnection; -import ch.naviqore.app.dto.TimeType; -import ch.naviqore.app.dto.TravelMode; -import ch.naviqore.service.*; +import ch.naviqore.app.dto.*; +import ch.naviqore.service.PublicTransitService; +import ch.naviqore.service.ScheduleInformationService; +import ch.naviqore.service.Stop; +import ch.naviqore.service.SupportedRoutingFeatures; import ch.naviqore.service.config.ConnectionQueryConfig; import ch.naviqore.service.exception.ConnectionRoutingException; import ch.naviqore.utils.spatial.GeoCoordinate; @@ -54,8 +53,8 @@ private static void handleConnectionRoutingException(ConnectionRoutingException public RoutingInfo getRoutingInfo() { SupportedRoutingFeatures features = service.getSupportedRoutingFeatures(); return new RoutingInfo(features.supportsMaxNumTransfers(), features.supportsMaxTravelTime(), - features.supportsMaxWalkingDuration(), features.supportsMinTransferDuration(), features.supportsAccessibility(), - features.supportsBikes(), features.supportsTravelModes()); + features.supportsMaxWalkingDuration(), features.supportsMinTransferDuration(), + features.supportsAccessibility(), features.supportsBikes(), features.supportsTravelModes()); } @Operation(summary = "Request connections between two stops or locations", description = "Requests connections between two stops or locations at a given departure / arrival datetime.") diff --git a/src/main/java/ch/naviqore/app/dto/RoutingInfo.java b/src/main/java/ch/naviqore/app/dto/RoutingInfo.java index b3304322..eb35c75a 100644 --- a/src/main/java/ch/naviqore/app/dto/RoutingInfo.java +++ b/src/main/java/ch/naviqore/app/dto/RoutingInfo.java @@ -1,4 +1,5 @@ package ch.naviqore.app.dto; + import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.ToString; @@ -7,6 +8,7 @@ @ToString @Getter public class RoutingInfo { + final boolean supportsMaxNumTransfers; final boolean supportsMaxTravelTime; final boolean supportsMaxWalkingDuration; @@ -14,4 +16,5 @@ public class RoutingInfo { final boolean supportsAccessibility; final boolean supportsBikes; final boolean supportsTravelModes; + } diff --git a/src/main/java/ch/naviqore/app/dto/ScheduleInfo.java b/src/main/java/ch/naviqore/app/dto/ScheduleInfo.java index 33edb167..e512c636 100644 --- a/src/main/java/ch/naviqore/app/dto/ScheduleInfo.java +++ b/src/main/java/ch/naviqore/app/dto/ScheduleInfo.java @@ -8,8 +8,10 @@ @ToString @Getter public class ScheduleInfo { + final boolean hasAccessibility; final boolean hasBikes; final boolean hasTravelModes; final ScheduleValidity scheduleValidity; + } diff --git a/src/main/java/ch/naviqore/raptor/RaptorAlgorithm.java b/src/main/java/ch/naviqore/raptor/RaptorAlgorithm.java index 89c99313..28d3da4c 100644 --- a/src/main/java/ch/naviqore/raptor/RaptorAlgorithm.java +++ b/src/main/java/ch/naviqore/raptor/RaptorAlgorithm.java @@ -1,9 +1,5 @@ package ch.naviqore.raptor; -import ch.naviqore.raptor.router.RaptorConfig; -import ch.naviqore.raptor.router.RaptorRouterBuilder; - -import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; import java.util.Map; diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsToRaptorConverter.java b/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsToRaptorConverter.java index e3cb78f6..e64f736a 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsToRaptorConverter.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/convert/GtfsToRaptorConverter.java @@ -5,7 +5,6 @@ import ch.naviqore.gtfs.schedule.model.StopTime; import ch.naviqore.gtfs.schedule.model.Transfer; import ch.naviqore.gtfs.schedule.type.TransferType; -import ch.naviqore.raptor.RaptorAlgorithm; import ch.naviqore.raptor.router.RaptorConfig; import ch.naviqore.raptor.router.RaptorRouter; import ch.naviqore.raptor.router.RaptorRouterBuilder; From c693bd8d7a6e08c81042c349bb38cec8f868adde Mon Sep 17 00:00:00 2001 From: Merlin Unterfinger Date: Fri, 23 Aug 2024 09:12:05 +0200 Subject: [PATCH 48/51] STYLE: NAV-131 - Remove "/" from schedule and routing info endpoints --- src/main/java/ch/naviqore/app/controller/RoutingController.java | 2 +- .../java/ch/naviqore/app/controller/ScheduleController.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ch/naviqore/app/controller/RoutingController.java b/src/main/java/ch/naviqore/app/controller/RoutingController.java index 095537f0..53c960ab 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingController.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingController.java @@ -49,7 +49,7 @@ private static void handleConnectionRoutingException(ConnectionRoutingException @Operation(summary = "Get information about the routing", description = "Get all relevant information about the routing features supported by the service.") @ApiResponse(responseCode = "200", description = "A list of routing features supported by the service.") - @GetMapping("/") + @GetMapping("") public RoutingInfo getRoutingInfo() { SupportedRoutingFeatures features = service.getSupportedRoutingFeatures(); return new RoutingInfo(features.supportsMaxNumTransfers(), features.supportsMaxTravelTime(), diff --git a/src/main/java/ch/naviqore/app/controller/ScheduleController.java b/src/main/java/ch/naviqore/app/controller/ScheduleController.java index acb38db8..d783c03d 100644 --- a/src/main/java/ch/naviqore/app/controller/ScheduleController.java +++ b/src/main/java/ch/naviqore/app/controller/ScheduleController.java @@ -32,7 +32,7 @@ public ScheduleController(ScheduleInformationService service) { @Operation(summary = "Get information about the schedule", description = "Get all relevant information about the schedule, such as supported features and validity.") @ApiResponse(responseCode = "200", description = "A list of details supported or not supported by the schedule and it's validity.") - @GetMapping("/") + @GetMapping("") public ScheduleInfo getScheduleInfo() { return new ScheduleInfo(service.hasAccessibilityInformation(), service.hasBikeInformation(), service.hasTravelModeInformation(), map(service.getValidity())); From b398ce17960969cf45ee27dda354410efef7b0bb Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Fri, 23 Aug 2024 09:29:23 +0200 Subject: [PATCH 49/51] STYLE: NAV-131 - Add assert to prevent IDE complaining. --- src/main/java/ch/naviqore/app/controller/RoutingController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/ch/naviqore/app/controller/RoutingController.java b/src/main/java/ch/naviqore/app/controller/RoutingController.java index 53c960ab..e6894808 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingController.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingController.java @@ -101,6 +101,7 @@ public List getConnections(@RequestParam(required = false) String so } else if (targetStop != null) { return map(service.getConnections(sourceCoordinate, targetStop, dateTime, map(timeType), config)); } else { + assert sourceCoordinate != null; // never happens --> see RoutingRequestValidator.validateStopParameters RoutingRequestValidator.validateCoordinates(sourceCoordinate, targetCoordinate); return map(service.getConnections(sourceCoordinate, targetCoordinate, dateTime, map(timeType), config)); } From a51784b8c0530fc432c0b51f960c7bcb4471ea64 Mon Sep 17 00:00:00 2001 From: Lukas Connolly Date: Fri, 23 Aug 2024 09:39:49 +0200 Subject: [PATCH 50/51] REFACTOR: NAV-131 - Renamce SupportedRoutingFeatures to RoutingFeatures. --- .../app/controller/RoutingController.java | 4 ++-- .../app/controller/RoutingRequestValidator.java | 16 +++++++--------- .../java/ch/naviqore/app/dto/RoutingInfo.java | 2 +- .../app/service/PublicTransitSpringService.java | 4 ++-- .../service/ConnectionRoutingService.java | 2 +- ...RoutingFeatures.java => RoutingFeatures.java} | 7 +++---- .../service/gtfs/raptor/GtfsRaptorService.java | 4 ++-- .../ch/naviqore/app/controller/DummyService.java | 4 ++-- 8 files changed, 20 insertions(+), 23 deletions(-) rename src/main/java/ch/naviqore/service/{SupportedRoutingFeatures.java => RoutingFeatures.java} (69%) diff --git a/src/main/java/ch/naviqore/app/controller/RoutingController.java b/src/main/java/ch/naviqore/app/controller/RoutingController.java index e6894808..0b4d9a27 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingController.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingController.java @@ -2,9 +2,9 @@ import ch.naviqore.app.dto.*; import ch.naviqore.service.PublicTransitService; +import ch.naviqore.service.RoutingFeatures; import ch.naviqore.service.ScheduleInformationService; import ch.naviqore.service.Stop; -import ch.naviqore.service.SupportedRoutingFeatures; import ch.naviqore.service.config.ConnectionQueryConfig; import ch.naviqore.service.exception.ConnectionRoutingException; import ch.naviqore.utils.spatial.GeoCoordinate; @@ -51,7 +51,7 @@ private static void handleConnectionRoutingException(ConnectionRoutingException @ApiResponse(responseCode = "200", description = "A list of routing features supported by the service.") @GetMapping("") public RoutingInfo getRoutingInfo() { - SupportedRoutingFeatures features = service.getSupportedRoutingFeatures(); + RoutingFeatures features = service.getRoutingFeatures(); return new RoutingInfo(features.supportsMaxNumTransfers(), features.supportsMaxTravelTime(), features.supportsMaxWalkingDuration(), features.supportsMinTransferDuration(), features.supportsAccessibility(), features.supportsBikes(), features.supportsTravelModes()); diff --git a/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java b/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java index 505ddf35..af777998 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingRequestValidator.java @@ -43,33 +43,31 @@ public static void validateQueryParams(int maxWalkingDuration, int maxTransferNu } // check support of routing features - if (maxWalkingDuration != Integer.MAX_VALUE && !service.getSupportedRoutingFeatures() - .supportsMaxWalkingDuration()) { + if (maxWalkingDuration != Integer.MAX_VALUE && !service.getRoutingFeatures().supportsMaxWalkingDuration()) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Max Walking Duration is not supported by the router of this service."); } - if (maxTransferNumber != Integer.MAX_VALUE && !service.getSupportedRoutingFeatures() - .supportsMaxNumTransfers()) { + if (maxTransferNumber != Integer.MAX_VALUE && !service.getRoutingFeatures().supportsMaxNumTransfers()) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Max Transfer Number is not supported by the router of this service."); } - if (maxTravelTime != Integer.MAX_VALUE && !service.getSupportedRoutingFeatures().supportsMaxTravelTime()) { + if (maxTravelTime != Integer.MAX_VALUE && !service.getRoutingFeatures().supportsMaxTravelTime()) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Max Travel Time is not supported by the router of this service."); } - if (minTransferTime != 0 && !service.getSupportedRoutingFeatures().supportsMinTransferDuration()) { + if (minTransferTime != 0 && !service.getRoutingFeatures().supportsMinTransferDuration()) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Min Transfer Duration is not supported by the router of this service."); } - if (wheelchairAccessible && !service.getSupportedRoutingFeatures().supportsAccessibility()) { + if (wheelchairAccessible && !service.getRoutingFeatures().supportsAccessibility()) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Wheelchair Accessible routing is not supported by the router of this service."); } - if (bikeAllowed && !service.getSupportedRoutingFeatures().supportsBikes()) { + if (bikeAllowed && !service.getRoutingFeatures().supportsBikes()) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Bike friendly routing is not supported by the router of this service."); } - if (!travelModes.containsAll(EnumSet.allOf(TravelMode.class)) && !service.getSupportedRoutingFeatures() + if (!travelModes.containsAll(EnumSet.allOf(TravelMode.class)) && !service.getRoutingFeatures() .supportsTravelModes()) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Filtering travel modes is not supported by the router of this service."); diff --git a/src/main/java/ch/naviqore/app/dto/RoutingInfo.java b/src/main/java/ch/naviqore/app/dto/RoutingInfo.java index eb35c75a..ff009235 100644 --- a/src/main/java/ch/naviqore/app/dto/RoutingInfo.java +++ b/src/main/java/ch/naviqore/app/dto/RoutingInfo.java @@ -16,5 +16,5 @@ public class RoutingInfo { final boolean supportsAccessibility; final boolean supportsBikes; final boolean supportsTravelModes; - + } diff --git a/src/main/java/ch/naviqore/app/service/PublicTransitSpringService.java b/src/main/java/ch/naviqore/app/service/PublicTransitSpringService.java index 504d30c0..9815e0d9 100644 --- a/src/main/java/ch/naviqore/app/service/PublicTransitSpringService.java +++ b/src/main/java/ch/naviqore/app/service/PublicTransitSpringService.java @@ -92,8 +92,8 @@ public List getNextDepartures(Stop stop, LocalDateTime from, @Nullable } @Override - public SupportedRoutingFeatures getSupportedRoutingFeatures() { - return delegate.getSupportedRoutingFeatures(); + public RoutingFeatures getRoutingFeatures() { + return delegate.getRoutingFeatures(); } @Override diff --git a/src/main/java/ch/naviqore/service/ConnectionRoutingService.java b/src/main/java/ch/naviqore/service/ConnectionRoutingService.java index 571979f8..652498ed 100644 --- a/src/main/java/ch/naviqore/service/ConnectionRoutingService.java +++ b/src/main/java/ch/naviqore/service/ConnectionRoutingService.java @@ -15,7 +15,7 @@ public interface ConnectionRoutingService { * * @return the supported routing features */ - SupportedRoutingFeatures getSupportedRoutingFeatures(); + RoutingFeatures getRoutingFeatures(); /** * Retrieves possible connections between two locations at a specified time. diff --git a/src/main/java/ch/naviqore/service/SupportedRoutingFeatures.java b/src/main/java/ch/naviqore/service/RoutingFeatures.java similarity index 69% rename from src/main/java/ch/naviqore/service/SupportedRoutingFeatures.java rename to src/main/java/ch/naviqore/service/RoutingFeatures.java index 7b6bf3b4..d2dfbda5 100644 --- a/src/main/java/ch/naviqore/service/SupportedRoutingFeatures.java +++ b/src/main/java/ch/naviqore/service/RoutingFeatures.java @@ -12,8 +12,7 @@ * @param supportsBikes whether the service supports routing for bike users * @param supportsTravelModes whether the service supports routing for different travel modes */ -public record SupportedRoutingFeatures(boolean supportsMaxNumTransfers, boolean supportsMaxTravelTime, - boolean supportsMaxWalkingDuration, boolean supportsMinTransferDuration, - boolean supportsAccessibility, boolean supportsBikes, - boolean supportsTravelModes) { +public record RoutingFeatures(boolean supportsMaxNumTransfers, boolean supportsMaxTravelTime, + boolean supportsMaxWalkingDuration, boolean supportsMinTransferDuration, + boolean supportsAccessibility, boolean supportsBikes, boolean supportsTravelModes) { } diff --git a/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java b/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java index b998a556..a48f7d07 100644 --- a/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java +++ b/src/main/java/ch/naviqore/service/gtfs/raptor/GtfsRaptorService.java @@ -154,8 +154,8 @@ public List getConnections(Stop source, Stop target, LocalDateTime t } @Override - public SupportedRoutingFeatures getSupportedRoutingFeatures() { - return new SupportedRoutingFeatures(true, true, true, true, schedule.hasTripAccessibilityInformation(), + public RoutingFeatures getRoutingFeatures() { + return new RoutingFeatures(true, true, true, true, schedule.hasTripAccessibilityInformation(), schedule.hasTripBikeInformation(), true); } diff --git a/src/test/java/ch/naviqore/app/controller/DummyService.java b/src/test/java/ch/naviqore/app/controller/DummyService.java index 96c65b33..44b3508f 100644 --- a/src/test/java/ch/naviqore/app/controller/DummyService.java +++ b/src/test/java/ch/naviqore/app/controller/DummyService.java @@ -75,8 +75,8 @@ public boolean isWithin(LocalDate date) { } @Override - public SupportedRoutingFeatures getSupportedRoutingFeatures() { - return new SupportedRoutingFeatures(supportsMaxTransferNumber, supportsMaxTravelTime, + public RoutingFeatures getRoutingFeatures() { + return new RoutingFeatures(supportsMaxTransferNumber, supportsMaxTravelTime, supportsMaxWalkingDuration, supportsMinTransferDuration, hasAccessibilityInformation, hasBikeInformation, hasTravelModeInformation); } From 4cbfc5bb793c81a8ffd9540c97dc426488ae055d Mon Sep 17 00:00:00 2001 From: Merlin Unterfinger Date: Fri, 23 Aug 2024 09:41:59 +0200 Subject: [PATCH 51/51] STYLE: NAV-131 - Format --- src/test/java/ch/naviqore/app/controller/DummyService.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/test/java/ch/naviqore/app/controller/DummyService.java b/src/test/java/ch/naviqore/app/controller/DummyService.java index 44b3508f..6fdd0be0 100644 --- a/src/test/java/ch/naviqore/app/controller/DummyService.java +++ b/src/test/java/ch/naviqore/app/controller/DummyService.java @@ -76,9 +76,8 @@ public boolean isWithin(LocalDate date) { @Override public RoutingFeatures getRoutingFeatures() { - return new RoutingFeatures(supportsMaxTransferNumber, supportsMaxTravelTime, - supportsMaxWalkingDuration, supportsMinTransferDuration, hasAccessibilityInformation, - hasBikeInformation, hasTravelModeInformation); + return new RoutingFeatures(supportsMaxTransferNumber, supportsMaxTravelTime, supportsMaxWalkingDuration, + supportsMinTransferDuration, hasAccessibilityInformation, hasBikeInformation, hasTravelModeInformation); } @Override