diff --git a/src/main/java/org/opentripplanner/client/OtpApiClient.java b/src/main/java/org/opentripplanner/client/OtpApiClient.java index 863d9d5..606044e 100644 --- a/src/main/java/org/opentripplanner/client/OtpApiClient.java +++ b/src/main/java/org/opentripplanner/client/OtpApiClient.java @@ -63,6 +63,7 @@ public TripPlan plan(TripPlanParameters req) throws IOException { req.time().toLocalDate().toString(), req.time().toLocalTime().truncatedTo(ChronoUnit.SECONDS).toString(), req.searchDirection().isArriveBy(), + req.searchWindow().map(sw -> "searchWindow : %d".formatted(sw.toSeconds())).orElse(""), req.walkReluctance(), req.wheelchair()); diff --git a/src/main/java/org/opentripplanner/client/parameters/TripPlanParameters.java b/src/main/java/org/opentripplanner/client/parameters/TripPlanParameters.java index 8ae3a94..e6879c9 100644 --- a/src/main/java/org/opentripplanner/client/parameters/TripPlanParameters.java +++ b/src/main/java/org/opentripplanner/client/parameters/TripPlanParameters.java @@ -1,29 +1,54 @@ package org.opentripplanner.client.parameters; +import java.time.Duration; import java.time.LocalDateTime; import java.util.Objects; +import java.util.Optional; import java.util.Set; + +import jakarta.annotation.Nullable; import org.opentripplanner.client.model.PlaceParameter; import org.opentripplanner.client.model.RequestMode; import org.opentripplanner.client.validation.CollectionUtils; -public record TripPlanParameters( - PlaceParameter fromPlace, - PlaceParameter toPlace, - LocalDateTime time, - int numItineraries, - Set modes, - SearchDirection searchDirection, - float walkReluctance, - boolean wheelchair) { - - public TripPlanParameters { - Objects.requireNonNull(fromPlace); - Objects.requireNonNull(toPlace); - Objects.requireNonNull(time); - Objects.requireNonNull(modes); +public final class TripPlanParameters { + private final PlaceParameter fromPlace; + private final PlaceParameter toPlace; + private final LocalDateTime time; + private final int numItineraries; + private final Set modes; + private final SearchDirection searchDirection; + @Nullable + private final Duration searchWindow; + private final float walkReluctance; + private final boolean wheelchair; + + public TripPlanParameters( + PlaceParameter fromPlace, + PlaceParameter toPlace, + LocalDateTime time, + int numItineraries, + Set modes, + SearchDirection searchDirection, + Duration searchWindow, + float walkReluctance, + boolean wheelchair + ) { CollectionUtils.assertHasValue(modes); - Objects.requireNonNull(searchDirection); + + this.fromPlace = Objects.requireNonNull(fromPlace); + this.toPlace = Objects.requireNonNull(toPlace); + this.time = Objects.requireNonNull(time); + this.numItineraries = numItineraries; + this.modes = Objects.requireNonNull(modes); + this.searchDirection = Objects.requireNonNull(searchDirection); + this.searchWindow = searchWindow; + this.walkReluctance = walkReluctance; + this.wheelchair = wheelchair; + } + + public Optional searchWindow() { + return Optional.ofNullable(searchWindow); } public enum SearchDirection { @@ -38,4 +63,98 @@ public boolean isArriveBy() { public static TripPlanParametersBuilder builder() { return new TripPlanParametersBuilder(); } + + public PlaceParameter fromPlace() { + return fromPlace; + } + + public PlaceParameter toPlace() { + return toPlace; + } + + public LocalDateTime time() { + return time; + } + + public int numItineraries() { + return numItineraries; + } + + public Set modes() { + return modes; + } + + public SearchDirection searchDirection() { + return searchDirection; + } + + public float walkReluctance() { + return walkReluctance; + } + + public boolean wheelchair() { + return wheelchair; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null || obj.getClass() != this.getClass()) return false; + var that = (TripPlanParameters) obj; + return Objects.equals(this.fromPlace, that.fromPlace) + && Objects.equals(this.toPlace, that.toPlace) + && Objects.equals(this.time, that.time) + && this.numItineraries == that.numItineraries + && Objects.equals(this.modes, that.modes) + && Objects.equals(this.searchDirection, that.searchDirection) + && Objects.equals(this.searchWindow, that.searchWindow) + && Float.floatToIntBits(this.walkReluctance) == Float.floatToIntBits(that.walkReluctance) + && this.wheelchair == that.wheelchair; + } + + @Override + public int hashCode() { + return Objects.hash( + fromPlace, + toPlace, + time, + numItineraries, + modes, + searchDirection, + searchWindow, + walkReluctance, + wheelchair); + } + + @Override + public String toString() { + return "TripPlanParameters[" + + "fromPlace=" + + fromPlace + + ", " + + "toPlace=" + + toPlace + + ", " + + "time=" + + time + + ", " + + "numItineraries=" + + numItineraries + + ", " + + "modes=" + + modes + + ", " + + "searchDirection=" + + searchDirection + + ", " + + "searchWindow=" + + searchWindow + + ", " + + "walkReluctance=" + + walkReluctance + + ", " + + "wheelchair=" + + wheelchair + + ']'; + } } diff --git a/src/main/java/org/opentripplanner/client/parameters/TripPlanParametersBuilder.java b/src/main/java/org/opentripplanner/client/parameters/TripPlanParametersBuilder.java index da2fcbf..8e6d64b 100644 --- a/src/main/java/org/opentripplanner/client/parameters/TripPlanParametersBuilder.java +++ b/src/main/java/org/opentripplanner/client/parameters/TripPlanParametersBuilder.java @@ -1,5 +1,6 @@ package org.opentripplanner.client.parameters; +import java.time.Duration; import java.time.LocalDateTime; import java.util.Arrays; import java.util.Set; @@ -14,6 +15,7 @@ public class TripPlanParametersBuilder { private LocalDateTime time; private Set modes; private SearchDirection searchDirection = SearchDirection.DEPART_AT; + private Duration searchWindow; private float walkReluctance = 1.4f; private int numItineraries = 5; private boolean wheelchair = false; @@ -48,6 +50,11 @@ public TripPlanParametersBuilder withSearchDirection(SearchDirection searchDirec return this; } + public TripPlanParametersBuilder withSearchWindow(Duration searchWindow) { + this.searchWindow = searchWindow; + return this; + } + public TripPlanParametersBuilder withWalkReluctance(float wr) { this.walkReluctance = wr; return this; @@ -70,6 +77,7 @@ public TripPlanParametersBuilder copy() { .withTime(time) .withModes(modes) .withSearchDirection(searchDirection) + .withSearchWindow(searchWindow) .withWalkReluctance(walkReluctance) .withNumberOfItineraries(numItineraries) .withWheelchair(wheelchair); @@ -83,6 +91,7 @@ public TripPlanParameters build() { numItineraries, modes, searchDirection, + searchWindow, walkReluctance, wheelchair); } diff --git a/src/main/resources/queries/plan.graphql b/src/main/resources/queries/plan.graphql index f944e21..ffb654d 100644 --- a/src/main/resources/queries/plan.graphql +++ b/src/main/resources/queries/plan.graphql @@ -7,6 +7,7 @@ query { date: "%s" time: "%s" arriveBy: %s + %s walkReluctance: %s wheelchair: %s ) { diff --git a/src/test/java/org/opentripplanner/IntegrationTest.java b/src/test/java/org/opentripplanner/IntegrationTest.java index fff2349..fefd449 100644 --- a/src/test/java/org/opentripplanner/IntegrationTest.java +++ b/src/test/java/org/opentripplanner/IntegrationTest.java @@ -9,6 +9,7 @@ import static org.opentripplanner.StationParameters.OSLO_WEST; import java.io.IOException; +import java.time.Duration; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.List; @@ -84,6 +85,34 @@ public void planPlaceToPlace() throws IOException { assertEquals(List.of(), leg.fareProducts()); } + @Test + public void planPlaceToPlaceWithSearchWindow() throws IOException { + var result = + client.plan( + TripPlanParameters.builder() + .withFrom(OSLO_LUFTHAVN_ID) + .withTo(OSLO_S_ID) + .withTime(LocalDateTime.now()) + .withModes(RequestMode.TRANSIT) + .withNumberOfItineraries(1) + .withSearchWindow(Duration.ofDays(1)) + .build()); + + LOG.info("Received {} itineraries", result.itineraries().size()); + assertEquals(1, result.itineraries().size()); + + assertNotNull(result.itineraries().get(0).legs().get(0).startTime()); + + var leg = result.itineraries().get(0).legs().get(0); + + var transitLeg = result.transitItineraries().get(0).transitLegs().get(0); + assertFalse(transitLeg.from().stop().isEmpty()); + assertFalse(transitLeg.to().stop().isEmpty()); + assertNotNull(transitLeg.from().stop().get().id()); + + assertEquals(List.of(), leg.fareProducts()); + } + @Test public void arriveByPlan() throws IOException { diff --git a/src/test/resources/logback.xml b/src/test/resources/logback-test.xml similarity index 100% rename from src/test/resources/logback.xml rename to src/test/resources/logback-test.xml