From 9035b1729865b478204432e50fa53e25fe862a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Tue, 27 Aug 2024 17:57:28 +0200 Subject: [PATCH 01/18] Move count parameter to filter parameters --- .../entur/lamassu/controller/GraphQLQueryController.java | 4 ++-- .../java/org/entur/lamassu/service/FilterParameters.java | 9 +++++++++ .../org/entur/lamassu/service/RangeQueryParameters.java | 8 -------- .../entur/lamassu/service/impl/GeoSearchServiceImpl.java | 6 ++++-- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/entur/lamassu/controller/GraphQLQueryController.java b/src/main/java/org/entur/lamassu/controller/GraphQLQueryController.java index 1f6410bd..6f087ed4 100644 --- a/src/main/java/org/entur/lamassu/controller/GraphQLQueryController.java +++ b/src/main/java/org/entur/lamassu/controller/GraphQLQueryController.java @@ -93,7 +93,6 @@ public Collection getVehicles( queryParams.setLat(lat); queryParams.setLon(lon); queryParams.setRange(range); - queryParams.setCount(count); var filterParams = new VehicleFilterParameters(); filterParams.setCodespaces(codespaces); @@ -103,6 +102,7 @@ public Collection getVehicles( filterParams.setPropulsionTypes(propulsionTypes); filterParams.setIncludeReserved(includeReserved); filterParams.setIncludeDisabled(includeDisabled); + filterParams.setCount(count); logger.debug("getVehicles called query={} filter={}", queryParams, filterParams); @@ -138,7 +138,6 @@ public Collection getStations( queryParams.setLat(lat); queryParams.setLon(lon); queryParams.setRange(range); - queryParams.setCount(count); var filterParams = new StationFilterParameters(); filterParams.setCodespaces(codespaces); @@ -146,6 +145,7 @@ public Collection getStations( filterParams.setOperators(operators); filterParams.setAvailableFormFactors(availableFormFactors); filterParams.setAvailablePropulsionTypes(availablePropulsionTypes); + filterParams.setCount(count); logger.debug("getStations called query={} filter={}", queryParams, filterParams); diff --git a/src/main/java/org/entur/lamassu/service/FilterParameters.java b/src/main/java/org/entur/lamassu/service/FilterParameters.java index 5307904a..a006a6bd 100644 --- a/src/main/java/org/entur/lamassu/service/FilterParameters.java +++ b/src/main/java/org/entur/lamassu/service/FilterParameters.java @@ -25,6 +25,7 @@ public class FilterParameters { private List codespaces; private List systems; private List operators; + private Integer count; public List getCodespaces() { return codespaces; @@ -49,4 +50,12 @@ public List getOperators() { public void setOperators(List operators) { this.operators = operators; } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } } diff --git a/src/main/java/org/entur/lamassu/service/RangeQueryParameters.java b/src/main/java/org/entur/lamassu/service/RangeQueryParameters.java index a35a7a1f..7ae5c71d 100644 --- a/src/main/java/org/entur/lamassu/service/RangeQueryParameters.java +++ b/src/main/java/org/entur/lamassu/service/RangeQueryParameters.java @@ -5,7 +5,6 @@ public class RangeQueryParameters { private Double lat; private Double lon; private Double range; - private Integer count; public Double getLat() { return lat; @@ -31,11 +30,4 @@ public void setRange(Double range) { this.range = range; } - public Integer getCount() { - return count; - } - - public void setCount(Integer count) { - this.count = count; - } } diff --git a/src/main/java/org/entur/lamassu/service/impl/GeoSearchServiceImpl.java b/src/main/java/org/entur/lamassu/service/impl/GeoSearchServiceImpl.java index 48298b98..aef7c060 100644 --- a/src/main/java/org/entur/lamassu/service/impl/GeoSearchServiceImpl.java +++ b/src/main/java/org/entur/lamassu/service/impl/GeoSearchServiceImpl.java @@ -52,7 +52,6 @@ public List getVehiclesNearby( Double longitude = rangeQueryParameters.getLon(); Double latitude = rangeQueryParameters.getLat(); Double range = rangeQueryParameters.getRange(); - Integer count = rangeQueryParameters.getCount(); List indexIds = vehicleSpatialIndex.radius( longitude, @@ -67,6 +66,8 @@ public List getVehiclesNearby( .filter(Objects::nonNull) .filter(id -> SpatialIndexIdFilter.filterVehicle(id, vehicleFilterParameters)); + Integer count = vehicleFilterParameters.getCount(); + if (count != null) { stream = stream.limit(count.longValue()); } @@ -86,7 +87,6 @@ public List getStationsNearby( Double longitude = rangeQueryParameters.getLon(); Double latitude = rangeQueryParameters.getLat(); Double range = rangeQueryParameters.getRange(); - Integer count = rangeQueryParameters.getCount(); List indexIds = stationSpatialIndex.radius( longitude, @@ -101,6 +101,8 @@ public List getStationsNearby( .filter(Objects::nonNull) .filter(id -> SpatialIndexIdFilter.filterStation(id, filterParameters)); + Integer count = filterParameters.getCount(); + if (count != null) { stream = stream.limit(count.longValue()); } From 8aa622768a468bbcb8cf685edca0b12ba57eaa7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Tue, 27 Aug 2024 19:49:21 +0200 Subject: [PATCH 02/18] Rename range service methods --- .../org/entur/lamassu/controller/GraphQLQueryController.java | 4 ++-- src/main/java/org/entur/lamassu/service/GeoSearchService.java | 4 ++-- .../org/entur/lamassu/service/impl/GeoSearchServiceImpl.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/entur/lamassu/controller/GraphQLQueryController.java b/src/main/java/org/entur/lamassu/controller/GraphQLQueryController.java index 6f087ed4..fe2f6dad 100644 --- a/src/main/java/org/entur/lamassu/controller/GraphQLQueryController.java +++ b/src/main/java/org/entur/lamassu/controller/GraphQLQueryController.java @@ -106,7 +106,7 @@ public Collection getVehicles( logger.debug("getVehicles called query={} filter={}", queryParams, filterParams); - return geoSearchService.getVehiclesNearby(queryParams, filterParams); + return geoSearchService.getVehiclesWithinRange(queryParams, filterParams); } public Vehicle getVehicle(String id) { @@ -149,7 +149,7 @@ public Collection getStations( logger.debug("getStations called query={} filter={}", queryParams, filterParams); - return geoSearchService.getStationsNearby(queryParams, filterParams); + return geoSearchService.getStationsWithinRange(queryParams, filterParams); } public Station getStation(String id) { diff --git a/src/main/java/org/entur/lamassu/service/GeoSearchService.java b/src/main/java/org/entur/lamassu/service/GeoSearchService.java index 0eb66b9f..86dd5154 100644 --- a/src/main/java/org/entur/lamassu/service/GeoSearchService.java +++ b/src/main/java/org/entur/lamassu/service/GeoSearchService.java @@ -6,11 +6,11 @@ import org.entur.lamassu.model.entities.Vehicle; public interface GeoSearchService { - List getVehiclesNearby( + List getVehiclesWithinRange( RangeQueryParameters rangeQueryParameters, VehicleFilterParameters vehicleFilterParameters ); - List getStationsNearby( + List getStationsWithinRange( RangeQueryParameters rangeQueryParameters, StationFilterParameters stationFilterParameters ); diff --git a/src/main/java/org/entur/lamassu/service/impl/GeoSearchServiceImpl.java b/src/main/java/org/entur/lamassu/service/impl/GeoSearchServiceImpl.java index aef7c060..9ba66e53 100644 --- a/src/main/java/org/entur/lamassu/service/impl/GeoSearchServiceImpl.java +++ b/src/main/java/org/entur/lamassu/service/impl/GeoSearchServiceImpl.java @@ -45,7 +45,7 @@ public GeoSearchServiceImpl( } @Override - public List getVehiclesNearby( + public List getVehiclesWithinRange( RangeQueryParameters rangeQueryParameters, VehicleFilterParameters vehicleFilterParameters ) { @@ -80,7 +80,7 @@ public List getVehiclesNearby( } @Override - public List getStationsNearby( + public List getStationsWithinRange( RangeQueryParameters rangeQueryParameters, StationFilterParameters filterParameters ) { From d5e06104e3094874f81d3ec1efd3fb1830a8305b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Wed, 28 Aug 2024 20:26:19 +0200 Subject: [PATCH 03/18] Implement bounding box search in geo search service --- pom.xml | 22 +++++ .../service/BoundingBoxQueryParameters.java | 59 +++++++++++++ .../lamassu/service/GeoSearchService.java | 8 ++ .../lamassu/service/RangeQueryParameters.java | 1 - .../service/impl/GeoSearchServiceImpl.java | 42 +++++++++ .../entur/lamassu/service/impl/GeoUtils.java | 86 +++++++++++++++++++ 6 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/entur/lamassu/service/BoundingBoxQueryParameters.java create mode 100644 src/main/java/org/entur/lamassu/service/impl/GeoUtils.java diff --git a/pom.xml b/pom.xml index d60314ea..dc35011b 100644 --- a/pom.xml +++ b/pom.xml @@ -207,6 +207,11 @@ mapbox-sdk-geojson 5.8.0 + + org.geotools + gt-main + 31.3 + @@ -356,4 +361,21 @@ + + + + osgeo + OSGeo Release Repository + https://repo.osgeo.org/repository/release/ + false + true + + + osgeo-snapshot + OSGeo Snapshot Repository + https://repo.osgeo.org/repository/snapshot/ + true + false + + diff --git a/src/main/java/org/entur/lamassu/service/BoundingBoxQueryParameters.java b/src/main/java/org/entur/lamassu/service/BoundingBoxQueryParameters.java new file mode 100644 index 00000000..b4163cb5 --- /dev/null +++ b/src/main/java/org/entur/lamassu/service/BoundingBoxQueryParameters.java @@ -0,0 +1,59 @@ +/* + * + * + * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * * the European Commission - subsequent versions of the EUPL (the "Licence"); + * * You may not use this work except in compliance with the Licence. + * * You may obtain a copy of the Licence at: + * * + * * https://joinup.ec.europa.eu/software/page/eupl + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the Licence is distributed on an "AS IS" basis, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the Licence for the specific language governing permissions and + * * limitations under the Licence. + * + */ + +package org.entur.lamassu.service; + +public class BoundingBoxQueryParameters { + + private Double minimumLatitude; + private Double minimumLongitude; + private Double maximumLatitude; + private Double maximumLongitude; + + public Double getMinimumLatitude() { + return minimumLatitude; + } + + public void setMinimumLatitude(Double minimumLatitude) { + this.minimumLatitude = minimumLatitude; + } + + public Double getMinimumLongitude() { + return minimumLongitude; + } + + public void setMinimumLongitude(Double minimumLongitude) { + this.minimumLongitude = minimumLongitude; + } + + public Double getMaximumLatitude() { + return maximumLatitude; + } + + public void setMaximumLatitude(Double maximumLatitude) { + this.maximumLatitude = maximumLatitude; + } + + public Double getMaximumLongitude() { + return maximumLongitude; + } + + public void setMaximumLongitude(Double maximumLongitude) { + this.maximumLongitude = maximumLongitude; + } +} diff --git a/src/main/java/org/entur/lamassu/service/GeoSearchService.java b/src/main/java/org/entur/lamassu/service/GeoSearchService.java index 86dd5154..9342fc6e 100644 --- a/src/main/java/org/entur/lamassu/service/GeoSearchService.java +++ b/src/main/java/org/entur/lamassu/service/GeoSearchService.java @@ -10,10 +10,18 @@ List getVehiclesWithinRange( RangeQueryParameters rangeQueryParameters, VehicleFilterParameters vehicleFilterParameters ); + List getVehiclesInBoundingBox( + BoundingBoxQueryParameters boundingBoxQueryParameters, + VehicleFilterParameters vehicleFilterParameters + ); List getStationsWithinRange( RangeQueryParameters rangeQueryParameters, StationFilterParameters stationFilterParameters ); + List getStationsInBoundingBox( + BoundingBoxQueryParameters boundingBoxQueryParameters, + StationFilterParameters stationFilterParameters + ); Collection getVehicleSpatialIndexOrphans(); Collection removeVehicleSpatialIndexOrphans(); } diff --git a/src/main/java/org/entur/lamassu/service/RangeQueryParameters.java b/src/main/java/org/entur/lamassu/service/RangeQueryParameters.java index 7ae5c71d..70aa914e 100644 --- a/src/main/java/org/entur/lamassu/service/RangeQueryParameters.java +++ b/src/main/java/org/entur/lamassu/service/RangeQueryParameters.java @@ -29,5 +29,4 @@ public Double getRange() { public void setRange(Double range) { this.range = range; } - } diff --git a/src/main/java/org/entur/lamassu/service/impl/GeoSearchServiceImpl.java b/src/main/java/org/entur/lamassu/service/impl/GeoSearchServiceImpl.java index 9ba66e53..99ef1a61 100644 --- a/src/main/java/org/entur/lamassu/service/impl/GeoSearchServiceImpl.java +++ b/src/main/java/org/entur/lamassu/service/impl/GeoSearchServiceImpl.java @@ -13,11 +13,13 @@ import org.entur.lamassu.cache.VehicleSpatialIndexId; import org.entur.lamassu.model.entities.Station; import org.entur.lamassu.model.entities.Vehicle; +import org.entur.lamassu.service.BoundingBoxQueryParameters; import org.entur.lamassu.service.GeoSearchService; import org.entur.lamassu.service.RangeQueryParameters; import org.entur.lamassu.service.StationFilterParameters; import org.entur.lamassu.service.VehicleFilterParameters; import org.entur.lamassu.util.SpatialIndexIdFilter; +import org.geotools.geometry.jts.ReferencedEnvelope; import org.redisson.api.GeoOrder; import org.redisson.api.GeoUnit; import org.springframework.beans.factory.annotation.Autowired; @@ -79,6 +81,27 @@ public List getVehiclesWithinRange( return vehicleCache.getAll(vehicleIds); } + @Override + public List getVehiclesInBoundingBox( + BoundingBoxQueryParameters boundingBoxQueryParameters, + VehicleFilterParameters vehicleFilterParameters + ) { + ReferencedEnvelope envelope = GeoUtils.mapToEnvelope(boundingBoxQueryParameters); + RangeQueryParameters rangeQueryParameters = GeoUtils.mapToRangeQueryParameters( + envelope + ); + + List vehicles = getVehiclesWithinRange( + rangeQueryParameters, + vehicleFilterParameters + ); + + return vehicles + .stream() + .filter(vehicle -> envelope.contains(vehicle.getLon(), vehicle.getLat())) + .toList(); + } + @Override public List getStationsWithinRange( RangeQueryParameters rangeQueryParameters, @@ -114,6 +137,25 @@ public List getStationsWithinRange( return stationCache.getAll(stationIds); } + @Override + public List getStationsInBoundingBox( + BoundingBoxQueryParameters boundingBoxQueryParameters, + StationFilterParameters stationFilterParameters + ) { + ReferencedEnvelope envelope = GeoUtils.mapToEnvelope(boundingBoxQueryParameters); + RangeQueryParameters rangeQueryParameters = GeoUtils.mapToRangeQueryParameters( + envelope + ); + List stations = getStationsWithinRange( + rangeQueryParameters, + stationFilterParameters + ); + return stations + .stream() + .filter(station -> envelope.contains(station.getLon(), station.getLat())) + .toList(); + } + @Override public Collection getVehicleSpatialIndexOrphans() { var indexIds = vehicleSpatialIndex.getAll(); diff --git a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java new file mode 100644 index 00000000..c5a818de --- /dev/null +++ b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java @@ -0,0 +1,86 @@ +/* + * + * + * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * * the European Commission - subsequent versions of the EUPL (the "Licence"); + * * You may not use this work except in compliance with the Licence. + * * You may obtain a copy of the Licence at: + * * + * * https://joinup.ec.europa.eu/software/page/eupl + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the Licence is distributed on an "AS IS" basis, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the Licence for the specific language governing permissions and + * * limitations under the Licence. + * + */ + +package org.entur.lamassu.service.impl; + +import org.entur.lamassu.service.BoundingBoxQueryParameters; +import org.entur.lamassu.service.RangeQueryParameters; +import org.geotools.api.referencing.operation.TransformException; +import org.geotools.geometry.jts.JTS; +import org.geotools.geometry.jts.ReferencedEnvelope; +import org.geotools.referencing.GeodeticCalculator; +import org.geotools.referencing.crs.DefaultGeographicCRS; +import org.jetbrains.annotations.NotNull; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.CoordinateXY; + +public class GeoUtils { + + /** + * Map the bounding box parameters to a geometric envelope + * @param boundingBoxQueryParameters + * @return + */ + public static @NotNull ReferencedEnvelope mapToEnvelope( + BoundingBoxQueryParameters boundingBoxQueryParameters + ) { + return new ReferencedEnvelope( + boundingBoxQueryParameters.getMinimumLongitude(), + boundingBoxQueryParameters.getMaximumLongitude(), + boundingBoxQueryParameters.getMinimumLatitude(), + boundingBoxQueryParameters.getMaximumLatitude(), + DefaultGeographicCRS.WGS84 + ); + } + + /** + * Uses the center of the envelope, and the radius of the circle the encloses the envelope to + * define the coordinates and range of the range query parameters. + * @param envelope + * @return + */ + public static @NotNull RangeQueryParameters mapToRangeQueryParameters( + ReferencedEnvelope envelope + ) { + RangeQueryParameters rangeQueryParameters = new RangeQueryParameters(); + rangeQueryParameters.setLon(envelope.getCenterX()); + rangeQueryParameters.setLat(envelope.getCenterY()); + rangeQueryParameters.setRange(getDiameter(envelope) / 2.0); + return rangeQueryParameters; + } + + /** + * Find the great circle distance between the southwest and northeast corners of the envelope, + * which we called the diameter of the envelope. + * @param envelope + * @return + */ + private static double getDiameter(ReferencedEnvelope envelope) { + try { + // TODO GeodeticCalculator not thread-safe, should be pooled + GeodeticCalculator gc = new GeodeticCalculator(DefaultGeographicCRS.WGS84); + Coordinate start = new CoordinateXY(envelope.getMinX(), envelope.getMinY()); + Coordinate end = new CoordinateXY(envelope.getMaxX(), envelope.getMaxY()); + gc.setStartingPosition(JTS.toDirectPosition(start, DefaultGeographicCRS.WGS84)); + gc.setDestinationPosition(JTS.toDirectPosition(end, DefaultGeographicCRS.WGS84)); + return gc.getOrthodromicDistance(); + } catch (TransformException e) { + throw new IllegalArgumentException(e); + } + } +} From dbc2c96f63dabfdff05d220f42acd8981446dbcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Wed, 28 Aug 2024 20:37:49 +0200 Subject: [PATCH 04/18] Add bbox search to controller and schema --- .../controller/GraphQLQueryController.java | 130 +++++++++++++++--- src/main/resources/graphql/schema.graphqls | 24 ++++ 2 files changed, 138 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/entur/lamassu/controller/GraphQLQueryController.java b/src/main/java/org/entur/lamassu/controller/GraphQLQueryController.java index fe2f6dad..76c48d0b 100644 --- a/src/main/java/org/entur/lamassu/controller/GraphQLQueryController.java +++ b/src/main/java/org/entur/lamassu/controller/GraphQLQueryController.java @@ -18,6 +18,7 @@ import org.entur.lamassu.model.entities.Station; import org.entur.lamassu.model.entities.Vehicle; import org.entur.lamassu.model.provider.FeedProvider; +import org.entur.lamassu.service.BoundingBoxQueryParameters; import org.entur.lamassu.service.FeedProviderService; import org.entur.lamassu.service.GeoSearchService; import org.entur.lamassu.service.RangeQueryParameters; @@ -71,6 +72,10 @@ public Collection getVehicles( Double lat, Double lon, Double range, + Double minimumLatitude, + Double minimumLongitude, + Double maximumLatitude, + Double maximumLongitude, Integer count, List codespaces, List systems, @@ -84,16 +89,10 @@ public Collection getVehicles( return vehicleCache.getAll(ids); } - validateRange(range); validateCount(count); validateCodespaces(codespaces); validateSystems(systems); - var queryParams = new RangeQueryParameters(); - queryParams.setLat(lat); - queryParams.setLon(lon); - queryParams.setRange(range); - var filterParams = new VehicleFilterParameters(); filterParams.setCodespaces(codespaces); filterParams.setSystems(systems); @@ -104,9 +103,53 @@ public Collection getVehicles( filterParams.setIncludeDisabled(includeDisabled); filterParams.setCount(count); - logger.debug("getVehicles called query={} filter={}", queryParams, filterParams); + if ( + isBoundingBoxSearch( + minimumLatitude, + minimumLongitude, + maximumLatitude, + maximumLongitude + ) + ) { + var boundingBoxQueryParameters = new BoundingBoxQueryParameters(); + boundingBoxQueryParameters.setMinimumLatitude(minimumLatitude); + boundingBoxQueryParameters.setMinimumLongitude(minimumLongitude); + boundingBoxQueryParameters.setMaximumLatitude(maximumLatitude); + boundingBoxQueryParameters.setMaximumLongitude(maximumLongitude); + + logger.debug( + "getVehicles called boundingBoxQueryParameters={} filter={}", + boundingBoxQueryParameters, + filterParams + ); + + return geoSearchService.getVehiclesInBoundingBox( + boundingBoxQueryParameters, + filterParams + ); + } else if (range != null && lat != null && lon != null) { + // add conditional to verify range search + validateRange(range); + + var rangeQueryParameters = new RangeQueryParameters(); + rangeQueryParameters.setLat(lat); + rangeQueryParameters.setLon(lon); + rangeQueryParameters.setRange(range); - return geoSearchService.getVehiclesWithinRange(queryParams, filterParams); + logger.debug( + "getVehicles called rangeQueryParameters={} filter={}", + rangeQueryParameters, + filterParams + ); + + return geoSearchService.getVehiclesWithinRange(rangeQueryParameters, filterParams); + } else { + throw new GraphqlErrorException.Builder() + .message( + "You must either specify lat, lon and range OR minimumLatitude, minimumLongitude, maximumLatitude and maximumLongitude" + ) + .build(); + } } public Vehicle getVehicle(String id) { @@ -118,6 +161,10 @@ public Collection getStations( Double lat, Double lon, Double range, + Double minimumLatitude, + Double minimumLongitude, + Double maximumLatitude, + Double maximumLongitude, Integer count, List codespaces, List systems, @@ -129,16 +176,10 @@ public Collection getStations( return stationCache.getAll(ids); } - validateRange(range); validateCount(count); validateCodespaces(codespaces); validateSystems(systems); - var queryParams = new RangeQueryParameters(); - queryParams.setLat(lat); - queryParams.setLon(lon); - queryParams.setRange(range); - var filterParams = new StationFilterParameters(); filterParams.setCodespaces(codespaces); filterParams.setSystems(systems); @@ -147,9 +188,66 @@ public Collection getStations( filterParams.setAvailablePropulsionTypes(availablePropulsionTypes); filterParams.setCount(count); - logger.debug("getStations called query={} filter={}", queryParams, filterParams); + if ( + isBoundingBoxSearch( + minimumLatitude, + minimumLongitude, + maximumLatitude, + maximumLongitude + ) + ) { + // TODO validate params, e.g. [(170,60), (-170,70)] + var boundingBoxQueryParameters = new BoundingBoxQueryParameters(); + boundingBoxQueryParameters.setMinimumLatitude(minimumLatitude); + boundingBoxQueryParameters.setMinimumLongitude(minimumLongitude); + boundingBoxQueryParameters.setMaximumLatitude(maximumLatitude); + boundingBoxQueryParameters.setMaximumLongitude(maximumLongitude); + logger.debug( + "getStations called boundingBoxQueryParameters={} filter={}", + boundingBoxQueryParameters, + filterParams + ); + return geoSearchService.getStationsInBoundingBox( + boundingBoxQueryParameters, + filterParams + ); + } else if (isRangeSearch(range, lat, lon)) { + validateRange(range); + var rangeQueryParameters = new RangeQueryParameters(); + rangeQueryParameters.setLat(lat); + rangeQueryParameters.setLon(lon); + rangeQueryParameters.setRange(range); + logger.debug( + "getStations called rangeQueryParameters={} filter={}", + rangeQueryParameters, + filterParams + ); + return geoSearchService.getStationsWithinRange(rangeQueryParameters, filterParams); + } else { + throw new GraphqlErrorException.Builder() + .message( + "You must either specify lat, lon and range OR minimumLatitude, minimumLongitude, maximumLatitude and maximumLongitude" + ) + .build(); + } + } - return geoSearchService.getStationsWithinRange(queryParams, filterParams); + private boolean isRangeSearch(Double range, Double lat, Double lon) { + return range != null && lat != null && lon != null; + } + + private boolean isBoundingBoxSearch( + Double minimumLatitude, + Double minimumLongitude, + Double maximumLatitude, + Double maximumLongitude + ) { + return ( + minimumLatitude != null && + minimumLongitude != null && + maximumLatitude != null && + maximumLongitude != null + ); } public Station getStation(String id) { diff --git a/src/main/resources/graphql/schema.graphqls b/src/main/resources/graphql/schema.graphqls index f1fbbd06..145eb18a 100644 --- a/src/main/resources/graphql/schema.graphqls +++ b/src/main/resources/graphql/schema.graphqls @@ -18,6 +18,18 @@ type Query { "Search radius in meters. Required unless using 'ids'" range: Int + "Bounding box minimum latitude" + minimumLatitude: Float + + "Bounding box minimum longitude" + minimumLongitude: Float + + "Bounding box maximum latitude" + maximumLatitude: Float + + "Bounding box maximum longitude" + maximumLongitude: Float + "Max results to return." count: Int @@ -58,6 +70,18 @@ type Query { "Search radius in meters. Required unless using 'ids'" range: Int + "Bounding box minimum latitude" + minimumLatitude: Float + + "Bounding box minimum longitude" + minimumLongitude: Float + + "Bounding box maximum latitude" + maximumLatitude: Float + + "Bounding box maximum longitude" + maximumLongitude: Float + "Max results to return." count: Int From 9e35e5989d7682c9c274c8750b0d8c78c4181b94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Wed, 28 Aug 2024 20:49:29 +0200 Subject: [PATCH 05/18] Add comments about how enclosing circle relates to envelope --- src/main/java/org/entur/lamassu/service/impl/GeoUtils.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java index c5a818de..b7e369a5 100644 --- a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java +++ b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java @@ -58,8 +58,14 @@ public class GeoUtils { ReferencedEnvelope envelope ) { RangeQueryParameters rangeQueryParameters = new RangeQueryParameters(); + + // The center of the circle that encloses the envelope is equal to the center + // of the envelope itself rangeQueryParameters.setLon(envelope.getCenterX()); rangeQueryParameters.setLat(envelope.getCenterY()); + + // The diameter of the circle that encloses the envelope is equal to the diameter + // of the envelope itself, hence half the diameter equals the circle's radius rangeQueryParameters.setRange(getDiameter(envelope) / 2.0); return rangeQueryParameters; } From 9b4b69cbfbf5c34841e0671233aa9d356d100b4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Thu, 29 Aug 2024 08:49:18 +0200 Subject: [PATCH 06/18] Make threadlocal singleton of geodetic calculator --- .../org/entur/lamassu/service/impl/GeoUtils.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java index b7e369a5..648551f2 100644 --- a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java +++ b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java @@ -78,8 +78,7 @@ public class GeoUtils { */ private static double getDiameter(ReferencedEnvelope envelope) { try { - // TODO GeodeticCalculator not thread-safe, should be pooled - GeodeticCalculator gc = new GeodeticCalculator(DefaultGeographicCRS.WGS84); + GeodeticCalculator gc = GeodeticCalculatorSingleton.getInstance(); Coordinate start = new CoordinateXY(envelope.getMinX(), envelope.getMinY()); Coordinate end = new CoordinateXY(envelope.getMaxX(), envelope.getMaxY()); gc.setStartingPosition(JTS.toDirectPosition(start, DefaultGeographicCRS.WGS84)); @@ -89,4 +88,17 @@ private static double getDiameter(ReferencedEnvelope envelope) { throw new IllegalArgumentException(e); } } + + // GeodeticCalculator not thread-safe, so we make thread-local singletons + private static class GeodeticCalculatorSingleton { + + private GeodeticCalculatorSingleton() {} + + private static final ThreadLocal _threadLocal = + ThreadLocal.withInitial(() -> new GeodeticCalculator(DefaultGeographicCRS.WGS84)); + + public static GeodeticCalculator getInstance() { + return _threadLocal.get(); + } + } } From ebde6b6a4afda8b2ca1c2f89dc7622e69863c8aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Thu, 29 Aug 2024 09:00:24 +0200 Subject: [PATCH 07/18] Add private constructor --- src/main/java/org/entur/lamassu/service/impl/GeoUtils.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java index 648551f2..76dc898f 100644 --- a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java +++ b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java @@ -30,6 +30,7 @@ import org.locationtech.jts.geom.CoordinateXY; public class GeoUtils { + private GeoUtils() {} /** * Map the bounding box parameters to a geometric envelope From 82b1399ee10096c4049978ddad71bc4446856e8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Tue, 3 Sep 2024 13:15:20 +0200 Subject: [PATCH 08/18] Use object pooling instead of threadlocal --- .../entur/lamassu/service/impl/GeoUtils.java | 46 +++++++++++++++---- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java index 76dc898f..ee6cdd16 100644 --- a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java +++ b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java @@ -18,6 +18,8 @@ package org.entur.lamassu.service.impl; +import java.util.LinkedList; +import java.util.Queue; import org.entur.lamassu.service.BoundingBoxQueryParameters; import org.entur.lamassu.service.RangeQueryParameters; import org.geotools.api.referencing.operation.TransformException; @@ -30,6 +32,7 @@ import org.locationtech.jts.geom.CoordinateXY; public class GeoUtils { + private GeoUtils() {} /** @@ -78,28 +81,53 @@ private GeoUtils() {} * @return */ private static double getDiameter(ReferencedEnvelope envelope) { + double distance = 0.0; try { - GeodeticCalculator gc = GeodeticCalculatorSingleton.getInstance(); + GeodeticCalculator gc = GeodeticCalculatorPoolManager.get(); Coordinate start = new CoordinateXY(envelope.getMinX(), envelope.getMinY()); Coordinate end = new CoordinateXY(envelope.getMaxX(), envelope.getMaxY()); gc.setStartingPosition(JTS.toDirectPosition(start, DefaultGeographicCRS.WGS84)); gc.setDestinationPosition(JTS.toDirectPosition(end, DefaultGeographicCRS.WGS84)); - return gc.getOrthodromicDistance(); + distance = gc.getOrthodromicDistance(); + GeodeticCalculatorPoolManager.release(gc); } catch (TransformException e) { throw new IllegalArgumentException(e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + if (distance == 0.0) { + throw new IllegalStateException(); } + + return distance; } - // GeodeticCalculator not thread-safe, so we make thread-local singletons - private static class GeodeticCalculatorSingleton { + private static class GeodeticCalculatorPoolManager { - private GeodeticCalculatorSingleton() {} + private static final Queue QUEUE = new LinkedList<>(); + private static final int POOL_SIZE = 10; - private static final ThreadLocal _threadLocal = - ThreadLocal.withInitial(() -> new GeodeticCalculator(DefaultGeographicCRS.WGS84)); + static { + for (int i = 0; i < POOL_SIZE; i++) { + QUEUE.add(new GeodeticCalculator(DefaultGeographicCRS.WGS84)); + } + } + + private static GeodeticCalculator get() throws InterruptedException { + synchronized (QUEUE) { + while (QUEUE.isEmpty()) { + QUEUE.wait(); + } + return QUEUE.poll(); + } + } - public static GeodeticCalculator getInstance() { - return _threadLocal.get(); + private static void release(GeodeticCalculator gc) { + synchronized (QUEUE) { + QUEUE.offer(gc); + QUEUE.notifyAll(); + } } } } From 9930b1bfef521afe0da52fcd488a5388df3942df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Tue, 3 Sep 2024 13:58:37 +0200 Subject: [PATCH 09/18] Rename method for clarity --- src/main/java/org/entur/lamassu/service/impl/GeoUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java index ee6cdd16..9ae89aaa 100644 --- a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java +++ b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java @@ -70,7 +70,7 @@ private GeoUtils() {} // The diameter of the circle that encloses the envelope is equal to the diameter // of the envelope itself, hence half the diameter equals the circle's radius - rangeQueryParameters.setRange(getDiameter(envelope) / 2.0); + rangeQueryParameters.setRange(getDiagonalLength(envelope) / 2.0); return rangeQueryParameters; } @@ -80,7 +80,7 @@ private GeoUtils() {} * @param envelope * @return */ - private static double getDiameter(ReferencedEnvelope envelope) { + private static double getDiagonalLength(ReferencedEnvelope envelope) { double distance = 0.0; try { GeodeticCalculator gc = GeodeticCalculatorPoolManager.get(); From f5276145f45a729351baa089b147a96487fedf11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Tue, 3 Sep 2024 14:05:50 +0200 Subject: [PATCH 10/18] Update comments to match --- src/main/java/org/entur/lamassu/service/impl/GeoUtils.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java index 9ae89aaa..2670c8f4 100644 --- a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java +++ b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java @@ -68,15 +68,15 @@ private GeoUtils() {} rangeQueryParameters.setLon(envelope.getCenterX()); rangeQueryParameters.setLat(envelope.getCenterY()); - // The diameter of the circle that encloses the envelope is equal to the diameter - // of the envelope itself, hence half the diameter equals the circle's radius + // The diameter of the circle that encloses the envelope is equal to the length + // of the diagonal of the envelope, hence half this length equals the circle's radius rangeQueryParameters.setRange(getDiagonalLength(envelope) / 2.0); return rangeQueryParameters; } /** * Find the great circle distance between the southwest and northeast corners of the envelope, - * which we called the diameter of the envelope. + * which we called the diagonal length of the envelope. * @param envelope * @return */ From 59296f19e94d0203e9e8e3ee9eb701c0115c5ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Tue, 3 Sep 2024 20:29:17 +0200 Subject: [PATCH 11/18] Improve object pooling implemetnation --- .../entur/lamassu/service/impl/GeoUtils.java | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java index 2670c8f4..44a045ed 100644 --- a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java +++ b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java @@ -81,26 +81,22 @@ private GeoUtils() {} * @return */ private static double getDiagonalLength(ReferencedEnvelope envelope) { - double distance = 0.0; + GeodeticCalculator gc = null; try { - GeodeticCalculator gc = GeodeticCalculatorPoolManager.get(); + gc = GeodeticCalculatorPoolManager.get(); Coordinate start = new CoordinateXY(envelope.getMinX(), envelope.getMinY()); Coordinate end = new CoordinateXY(envelope.getMaxX(), envelope.getMaxY()); gc.setStartingPosition(JTS.toDirectPosition(start, DefaultGeographicCRS.WGS84)); gc.setDestinationPosition(JTS.toDirectPosition(end, DefaultGeographicCRS.WGS84)); - distance = gc.getOrthodromicDistance(); - GeodeticCalculatorPoolManager.release(gc); + return gc.getOrthodromicDistance(); } catch (TransformException e) { throw new IllegalArgumentException(e); } catch (InterruptedException e) { Thread.currentThread().interrupt(); + throw new IllegalStateException("Unable to calculate diagonal length of envelope", e); + } finally { + GeodeticCalculatorPoolManager.release(gc); } - - if (distance == 0.0) { - throw new IllegalStateException(); - } - - return distance; } private static class GeodeticCalculatorPoolManager { @@ -124,9 +120,11 @@ private static GeodeticCalculator get() throws InterruptedException { } private static void release(GeodeticCalculator gc) { - synchronized (QUEUE) { - QUEUE.offer(gc); - QUEUE.notifyAll(); + if (gc != null) { + synchronized (QUEUE) { + QUEUE.offer(gc); + QUEUE.notifyAll(); + } } } } From 91d0d43a932f53010270ac4accdd45d7be46a46a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Thu, 5 Sep 2024 10:20:15 +0200 Subject: [PATCH 12/18] Formatting --- src/main/java/org/entur/lamassu/service/impl/GeoUtils.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java index 44a045ed..7819f554 100644 --- a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java +++ b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java @@ -93,7 +93,10 @@ private static double getDiagonalLength(ReferencedEnvelope envelope) { throw new IllegalArgumentException(e); } catch (InterruptedException e) { Thread.currentThread().interrupt(); - throw new IllegalStateException("Unable to calculate diagonal length of envelope", e); + throw new IllegalStateException( + "Unable to calculate diagonal length of envelope", + e + ); } finally { GeodeticCalculatorPoolManager.release(gc); } From b156c5f683d214f043373e395b2c82f3939d9e2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Thu, 5 Sep 2024 11:36:57 +0200 Subject: [PATCH 13/18] Use apache commons object pooling --- .../entur/lamassu/service/impl/GeoUtils.java | 59 +++++++++++-------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java index 7819f554..d2689a53 100644 --- a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java +++ b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java @@ -18,8 +18,9 @@ package org.entur.lamassu.service.impl; -import java.util.LinkedList; -import java.util.Queue; +import org.apache.commons.pool.BasePoolableObjectFactory; +import org.apache.commons.pool.PoolableObjectFactory; +import org.apache.commons.pool.impl.GenericObjectPool; import org.entur.lamassu.service.BoundingBoxQueryParameters; import org.entur.lamassu.service.RangeQueryParameters; import org.geotools.api.referencing.operation.TransformException; @@ -83,7 +84,7 @@ private GeoUtils() {} private static double getDiagonalLength(ReferencedEnvelope envelope) { GeodeticCalculator gc = null; try { - gc = GeodeticCalculatorPoolManager.get(); + gc = GeodeticCalculatorPoolManager.getInstance().get(); Coordinate start = new CoordinateXY(envelope.getMinX(), envelope.getMinY()); Coordinate end = new CoordinateXY(envelope.getMaxX(), envelope.getMaxY()); gc.setStartingPosition(JTS.toDirectPosition(start, DefaultGeographicCRS.WGS84)); @@ -97,37 +98,49 @@ private static double getDiagonalLength(ReferencedEnvelope envelope) { "Unable to calculate diagonal length of envelope", e ); + } catch (Exception e) { + throw new RuntimeException(e); } finally { - GeodeticCalculatorPoolManager.release(gc); + GeodeticCalculatorPoolManager.getInstance().release(gc); } } private static class GeodeticCalculatorPoolManager { - private static final Queue QUEUE = new LinkedList<>(); - private static final int POOL_SIZE = 10; + // pool size can be high, purpose is to not share instances between threads + private static final int POOL_SIZE = 100; + private static final GeodeticCalculatorPoolManager INSTANCE = + new GeodeticCalculatorPoolManager(); - static { - for (int i = 0; i < POOL_SIZE; i++) { - QUEUE.add(new GeodeticCalculator(DefaultGeographicCRS.WGS84)); - } + private final GenericObjectPool pool; + + private GeodeticCalculatorPoolManager() { + GenericObjectPool.Config config = new GenericObjectPool.Config(); + config.maxActive = POOL_SIZE; + PoolableObjectFactory geodeticCalculatorFactory = + new BasePoolableObjectFactory<>() { + @Override + public GeodeticCalculator makeObject() { + return new GeodeticCalculator(DefaultGeographicCRS.WGS84); + } + }; + + pool = new GenericObjectPool<>(geodeticCalculatorFactory, config); } - private static GeodeticCalculator get() throws InterruptedException { - synchronized (QUEUE) { - while (QUEUE.isEmpty()) { - QUEUE.wait(); - } - return QUEUE.poll(); - } + public static GeodeticCalculatorPoolManager getInstance() { + return INSTANCE; + } + + private GeodeticCalculator get() throws Exception { + return pool.borrowObject(); } - private static void release(GeodeticCalculator gc) { - if (gc != null) { - synchronized (QUEUE) { - QUEUE.offer(gc); - QUEUE.notifyAll(); - } + private void release(GeodeticCalculator gc) { + try { + pool.returnObject(gc); + } catch (Exception e) { + throw new RuntimeException(e); } } } From 8de282a71c15fb846ab81330685f97d536fcf52f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Thu, 5 Sep 2024 11:39:28 +0200 Subject: [PATCH 14/18] Cleanup --- .../entur/lamassu/service/impl/GeoUtils.java | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java index d2689a53..89ed9405 100644 --- a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java +++ b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java @@ -82,16 +82,18 @@ private GeoUtils() {} * @return */ private static double getDiagonalLength(ReferencedEnvelope envelope) { - GeodeticCalculator gc = null; + GeodeticCalculator geodeticCalculator = null; try { - gc = GeodeticCalculatorPoolManager.getInstance().get(); + geodeticCalculator = GeodeticCalculatorPoolManager.getInstance().get(); Coordinate start = new CoordinateXY(envelope.getMinX(), envelope.getMinY()); Coordinate end = new CoordinateXY(envelope.getMaxX(), envelope.getMaxY()); - gc.setStartingPosition(JTS.toDirectPosition(start, DefaultGeographicCRS.WGS84)); - gc.setDestinationPosition(JTS.toDirectPosition(end, DefaultGeographicCRS.WGS84)); - return gc.getOrthodromicDistance(); - } catch (TransformException e) { - throw new IllegalArgumentException(e); + geodeticCalculator.setStartingPosition( + JTS.toDirectPosition(start, DefaultGeographicCRS.WGS84) + ); + geodeticCalculator.setDestinationPosition( + JTS.toDirectPosition(end, DefaultGeographicCRS.WGS84) + ); + return geodeticCalculator.getOrthodromicDistance(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new IllegalStateException( @@ -99,9 +101,12 @@ private static double getDiagonalLength(ReferencedEnvelope envelope) { e ); } catch (Exception e) { - throw new RuntimeException(e); + throw new IllegalStateException( + "Unable to calculate diagonal length of envelope", + e + ); } finally { - GeodeticCalculatorPoolManager.getInstance().release(gc); + GeodeticCalculatorPoolManager.getInstance().release(geodeticCalculator); } } From 49456a179b6c7494d1a442de3ddad3bb5805c31f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Thu, 5 Sep 2024 15:23:59 +0200 Subject: [PATCH 15/18] Add simple integration test for bbox query --- .../integration/GraphQLIntegrationTest.java | 16 ++++++++++++++++ src/test/resources/vehicles_bbox_query.graphql | 14 ++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/test/resources/vehicles_bbox_query.graphql diff --git a/src/test/java/org/entur/lamassu/integration/GraphQLIntegrationTest.java b/src/test/java/org/entur/lamassu/integration/GraphQLIntegrationTest.java index bbeb775a..ab440160 100644 --- a/src/test/java/org/entur/lamassu/integration/GraphQLIntegrationTest.java +++ b/src/test/java/org/entur/lamassu/integration/GraphQLIntegrationTest.java @@ -178,4 +178,20 @@ public void testUnknownOperatorDoesNotThrow() throws IOException { .isEmpty() ); } + + @Test + public void testVehiclesBoundingBoxQuery() throws IOException { + GraphQLResponse response = graphQLTestTemplate.postForResource( + "vehicles_bbox_query.graphql" + ); + assertEquals(HttpStatus.OK, response.getStatusCode()); + + assertEquals( + 2, + JsonPath + .parse(response.getRawResponse().getBody()) + .read("$.data.vehicles", List.class) + .size() + ); + } } diff --git a/src/test/resources/vehicles_bbox_query.graphql b/src/test/resources/vehicles_bbox_query.graphql new file mode 100644 index 00000000..643a323d --- /dev/null +++ b/src/test/resources/vehicles_bbox_query.graphql @@ -0,0 +1,14 @@ +{ + vehicles( + minimumLongitude: 10.0, + minimumLatitude: 59.0, + maximumLongitude: 11.0 + maximumLatitude: 60.0 + count: 2, + includeDisabled: true + ) { + id + lat + lon + } +} From e6f783f9b52c6fcaccdee4418d806f33fc0e3fe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Thu, 5 Sep 2024 15:34:22 +0200 Subject: [PATCH 16/18] Add simple integration test for stations bbox query --- .../integration/GraphQLIntegrationTest.java | 15 +++++++++++++++ src/test/resources/stations_bbox_query.graphql | 14 ++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/test/resources/stations_bbox_query.graphql diff --git a/src/test/java/org/entur/lamassu/integration/GraphQLIntegrationTest.java b/src/test/java/org/entur/lamassu/integration/GraphQLIntegrationTest.java index ab440160..394ecb0b 100644 --- a/src/test/java/org/entur/lamassu/integration/GraphQLIntegrationTest.java +++ b/src/test/java/org/entur/lamassu/integration/GraphQLIntegrationTest.java @@ -194,4 +194,19 @@ public void testVehiclesBoundingBoxQuery() throws IOException { .size() ); } + + @Test + public void testStationsBoundingBoxQuery() throws IOException { + GraphQLResponse response = graphQLTestTemplate.postForResource( + "stations_bbox_query.graphql" + ); + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertEquals( + 1, + JsonPath + .parse(response.getRawResponse().getBody()) + .read("$.data.stations", List.class) + .size() + ); + } } diff --git a/src/test/resources/stations_bbox_query.graphql b/src/test/resources/stations_bbox_query.graphql new file mode 100644 index 00000000..afe332c4 --- /dev/null +++ b/src/test/resources/stations_bbox_query.graphql @@ -0,0 +1,14 @@ +{ + stations( + minimumLongitude: 44.0, + minimumLatitude: 11.0, + maximumLongitude: 45.0 + maximumLatitude: 12.0 + count: 1 + ) { + id + lat + lon + } +} +, From ae3807e64a3786c65af6158f62b4a6248185114e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Fri, 6 Sep 2024 08:32:27 +0200 Subject: [PATCH 17/18] Remove unused import --- src/main/java/org/entur/lamassu/service/impl/GeoUtils.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java index 89ed9405..a3fae703 100644 --- a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java +++ b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java @@ -23,7 +23,6 @@ import org.apache.commons.pool.impl.GenericObjectPool; import org.entur.lamassu.service.BoundingBoxQueryParameters; import org.entur.lamassu.service.RangeQueryParameters; -import org.geotools.api.referencing.operation.TransformException; import org.geotools.geometry.jts.JTS; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.referencing.GeodeticCalculator; From 88b8ac8f2ade7ed20e2f4ead3692712a10cf6493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Fri, 6 Sep 2024 08:36:53 +0200 Subject: [PATCH 18/18] Cleanup --- .../org/entur/lamassu/controller/GraphQLQueryController.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/entur/lamassu/controller/GraphQLQueryController.java b/src/main/java/org/entur/lamassu/controller/GraphQLQueryController.java index 76c48d0b..fc3f43fa 100644 --- a/src/main/java/org/entur/lamassu/controller/GraphQLQueryController.java +++ b/src/main/java/org/entur/lamassu/controller/GraphQLQueryController.java @@ -127,8 +127,7 @@ public Collection getVehicles( boundingBoxQueryParameters, filterParams ); - } else if (range != null && lat != null && lon != null) { - // add conditional to verify range search + } else if (isRangeSearch(range, lat, lon)) { validateRange(range); var rangeQueryParameters = new RangeQueryParameters(); @@ -196,7 +195,6 @@ public Collection getStations( maximumLongitude ) ) { - // TODO validate params, e.g. [(170,60), (-170,70)] var boundingBoxQueryParameters = new BoundingBoxQueryParameters(); boundingBoxQueryParameters.setMinimumLatitude(minimumLatitude); boundingBoxQueryParameters.setMinimumLongitude(minimumLongitude);