Skip to content

Commit

Permalink
Merge pull request #100 from naviqore/NAV-131-Extend-QueryConfig-for-…
Browse files Browse the repository at this point in the history
…Raptor

Nav 131 extend query config for raptor
  • Loading branch information
munterfi authored Aug 23, 2024
2 parents d57387f + 4cbfc5b commit 6ea7802
Show file tree
Hide file tree
Showing 44 changed files with 1,075 additions and 206 deletions.
46 changes: 35 additions & 11 deletions src/main/java/ch/naviqore/app/controller/RoutingController.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package ch.naviqore.app.controller;

import ch.naviqore.app.dto.Connection;
import ch.naviqore.app.dto.StopConnection;
import ch.naviqore.app.dto.TimeType;
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.config.ConnectionQueryConfig;
Expand All @@ -25,6 +24,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;
Expand All @@ -47,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() {
RoutingFeatures features = service.getRoutingFeatures();
return new RoutingInfo(features.supportsMaxNumTransfers(), features.supportsMaxTravelTime(),
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.")
@ApiResponse(responseCode = "200", description = "A list of connections between the specified stops.")
@ApiResponse(responseCode = "400", description = "Invalid input parameters", content = @Content(schema = @Schema()))
Expand All @@ -63,8 +73,10 @@ public List<Connection> 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<TravelMode> travelModes) {
// get coordinates if available
GeoCoordinate sourceCoordinate = Utils.getCoordinateIfAvailable(sourceStopId, sourceLatitude, sourceLongitude,
GlobalValidator.StopType.SOURCE);
Expand All @@ -78,8 +90,7 @@ public List<Connection> 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) {
Expand All @@ -90,6 +101,8 @@ public List<Connection> 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));
}
} catch (ConnectionRoutingException e) {
Expand All @@ -112,6 +125,9 @@ public List<StopConnection> 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<TravelMode> travelModes,
@RequestParam(required = false, defaultValue = "false") boolean returnConnections) {

// get stops or coordinates if available
Expand All @@ -122,7 +138,7 @@ public List<StopConnection> 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 {
Expand Down Expand Up @@ -156,17 +172,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<TravelMode> 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, map(travelModes));
}

private static int setToMaxIfNull(Integer value) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package ch.naviqore.app.controller;

import ch.naviqore.app.dto.TravelMode;
import ch.naviqore.service.PublicTransitService;
import ch.naviqore.utils.spatial.GeoCoordinate;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.jetbrains.annotations.Nullable;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;

import java.util.EnumSet;

@NoArgsConstructor(access = AccessLevel.NONE)
final class RoutingRequestValidator {

Expand All @@ -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<TravelMode> travelModes, PublicTransitService service) {
if (maxWalkingDuration < 0) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
"Max walking duration must be greater than or equal to 0.");
Expand All @@ -36,6 +41,37 @@ 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.");
}

// check support of routing features
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.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.getRoutingFeatures().supportsMaxTravelTime()) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
"Max Travel Time is not supported by the router of this service.");
}
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.getRoutingFeatures().supportsAccessibility()) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
"Wheelchair Accessible routing is not supported by the router of this service.");
}
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.getRoutingFeatures()
.supportsTravelModes()) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
"Filtering travel modes is not supported by the router of this service.");
}
}

public static void validateStopParameters(@Nullable String stopId, @Nullable Double latitude,
Expand All @@ -62,4 +98,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.");
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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()))
Expand Down
46 changes: 32 additions & 14 deletions src/main/java/ch/naviqore/app/dto/DtoMapper.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
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;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -34,26 +34,40 @@ 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) {
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<ch.naviqore.service.TravelMode> map(EnumSet<TravelMode> travelModes) {
EnumSet<ch.naviqore.service.TravelMode> 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 TimeType map(ch.naviqore.app.dto.TimeType timeType) {
public static ch.naviqore.service.TimeType map(TimeType timeType) {
return switch (timeType) {
case DEPARTURE -> TimeType.DEPARTURE;
case ARRIVAL -> TimeType.ARRIVAL;
case ARRIVAL -> ch.naviqore.service.TimeType.ARRIVAL;
case DEPARTURE -> ch.naviqore.service.TimeType.DEPARTURE;
};
}

Expand All @@ -67,14 +81,18 @@ public static List<Connection> map(List<ch.naviqore.service.Connection> connecti
}

public static List<StopConnection> map(Map<ch.naviqore.service.Stop, ch.naviqore.service.Connection> connections,
ch.naviqore.app.dto.TimeType timeType, boolean returnConnections) {
TimeType timeType, boolean returnConnections) {
List<StopConnection> arrivals = new ArrayList<>();
for (Map.Entry<ch.naviqore.service.Stop, ch.naviqore.service.Connection> 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;
}

public static ScheduleValidity map(ch.naviqore.service.Validity validity) {
return new ScheduleValidity(validity.getStartDate(), validity.getEndDate());
}

private static class LegVisitorImpl implements LegVisitor<Leg> {
@Override
public Leg visit(PublicTransitLeg publicTransitLeg) {
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/ch/naviqore/app/dto/Route.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

}

20 changes: 20 additions & 0 deletions src/main/java/ch/naviqore/app/dto/RoutingInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
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 supportsMaxWalkingDuration;
final boolean supportsMinTransferDuration;
final boolean supportsAccessibility;
final boolean supportsBikes;
final boolean supportsTravelModes;

}
17 changes: 17 additions & 0 deletions src/main/java/ch/naviqore/app/dto/ScheduleInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ch.naviqore.app.dto;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;

@RequiredArgsConstructor
@ToString
@Getter
public class ScheduleInfo {

final boolean hasAccessibility;
final boolean hasBikes;
final boolean hasTravelModes;
final ScheduleValidity scheduleValidity;

}
17 changes: 17 additions & 0 deletions src/main/java/ch/naviqore/app/dto/ScheduleValidity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
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;
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
final LocalDate endDate;
}
4 changes: 3 additions & 1 deletion src/main/java/ch/naviqore/app/dto/StopConnection.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ch.naviqore.app.dto;

import ch.naviqore.service.TimeType;
import lombok.*;

import java.time.LocalDateTime;
Expand Down Expand Up @@ -109,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);
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/ch/naviqore/app/dto/TimeType.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package ch.naviqore.app.dto;

public enum TimeType {
DEPARTURE,
ARRIVAL
ARRIVAL,
DEPARTURE
}
Loading

0 comments on commit 6ea7802

Please sign in to comment.