diff --git a/src/community/ogcapi/dggs/dggs-core/src/main/java/org/geotools/dggs/gstore/DGGSResolutionCalculator.java b/src/community/ogcapi/dggs/dggs-core/src/main/java/org/geotools/dggs/gstore/DGGSResolutionCalculator.java index 0e7067603bf..c87ee5fb7da 100644 --- a/src/community/ogcapi/dggs/dggs-core/src/main/java/org/geotools/dggs/gstore/DGGSResolutionCalculator.java +++ b/src/community/ogcapi/dggs/dggs-core/src/main/java/org/geotools/dggs/gstore/DGGSResolutionCalculator.java @@ -103,11 +103,7 @@ public int getTargetResolution(Query query, int defaultResolution) { if (sd != null) { distance = Optional.of(scaleToDistance(DefaultGeographicCRS.WGS84, sd)); } else { - distance = - Optional.ofNullable(hints.get(Hints.GEOMETRY_DISTANCE)) - .filter(Number.class::isInstance) - .map(Number.class::cast) - .map(n -> n.doubleValue()); + distance = getDoubleHint(hints, Hints.GEOMETRY_DISTANCE); } // do we have a resoution delta? @@ -139,8 +135,15 @@ public int getTargetResolution(Query query, int defaultResolution) { * Optional}. */ private Optional getIntegerHint(Hints hints, Object key) { - return Optional.ofNullable((Integer) hints.get(key)) - .map(n -> safeConvert(n, Integer.class)); + return Optional.ofNullable(hints.get(key)).map(n -> safeConvert(n, Integer.class)); + } + + /** + * Given the hints and a key, returns the double value associated with the key, as an {@link + * Optional}. + */ + private Optional getDoubleHint(Hints hints, Object key) { + return Optional.ofNullable(hints.get(key)).map(n -> safeConvert(n, Double.class)); } /** diff --git a/src/community/ogcapi/dggs/dggs-core/src/test/java/org/geotools/dggs/gstore/DGGSResolutionCalculatorTest.java b/src/community/ogcapi/dggs/dggs-core/src/test/java/org/geotools/dggs/gstore/DGGSResolutionCalculatorTest.java index ad65cdb1235..9e69c2a75cd 100644 --- a/src/community/ogcapi/dggs/dggs-core/src/test/java/org/geotools/dggs/gstore/DGGSResolutionCalculatorTest.java +++ b/src/community/ogcapi/dggs/dggs-core/src/test/java/org/geotools/dggs/gstore/DGGSResolutionCalculatorTest.java @@ -81,6 +81,21 @@ public void testGetResolutionMin() { assertEquals(5, resolution); } + /** When the minimim resolution comes from the GeoServer configuration, it might be a string */ + @Test + public void testGetResolutionMinString() { + Query query = new Query("testLayer"); + Hints hints = new Hints(); + hints.put(Hints.GEOMETRY_DISTANCE, 10d); // 10 degrees + hints.put( + DGGSResolutionCalculator.MINRES_HINTS_KEY, + String.valueOf("5")); // min resolution is 5 + query.setHints(hints); + + int resolution = calculator.getTargetResolution(query, 1); + assertEquals(5, resolution); + } + @Test public void testGetTargetResolutionDistanceSmall() { Query query = new Query("testLayer"); @@ -104,6 +119,18 @@ public void testGetResolutionMax() { assertEquals(2, resolution); } + @Test + public void testGetResolutionMaxString() { + Query query = new Query("testLayer"); + Hints hints = new Hints(); + hints.put(Hints.GEOMETRY_DISTANCE, 0.001); // in degrees + hints.put(DGGSResolutionCalculator.MAXRES_HINTS_KEY, String.valueOf(2)); + query.setHints(hints); + + int resolution = calculator.getTargetResolution(query, 1); + assertEquals(2, resolution); + } + @Test public void testGetTargetResolutionDistanceOffset() { Query query = new Query("testLayer"); @@ -117,10 +144,23 @@ public void testGetTargetResolutionDistanceOffset() { } @Test - public void testGetTargetResolutionExplicit() { + public void testGetTargetResolutionDistanceOffsetString() { Query query = new Query("testLayer"); Hints hints = new Hints(); - hints.put(Hints.VIRTUAL_TABLE_PARAMETERS, Map.of(DGGSStore.VP_RESOLUTION, 5)); + hints.put(Hints.GEOMETRY_DISTANCE, 10d); // 10 degrees + hints.put(DGGSResolutionCalculator.OFFSET_HINTS_KEY, String.valueOf("1")); + query.setHints(hints); + + int resolution = calculator.getTargetResolution(query, 1); + assertEquals(1, resolution); + } + + @Test + public void testGetTargetResolutionString() { + Query query = new Query("testLayer"); + Hints hints = new Hints(); + hints.put( + Hints.VIRTUAL_TABLE_PARAMETERS, Map.of(DGGSStore.VP_RESOLUTION, String.valueOf(5))); query.setHints(hints); int resolution = calculator.getTargetResolution(query, 1); @@ -139,4 +179,21 @@ public void testGetTargetResolutionWMSScale() { EnvFunction.clearLocalValues(); } } + + /** + * This one should not actually happen, but just to be on the safe side, make sure code works + * even if the scale denominator is a string + */ + @Test + public void testGetTargetResolutionWMSScaleString() { + EnvFunction.setLocalValues( + Map.of(DGGSResolutionCalculator.WMS_SCALE_DENOMINATOR, String.valueOf(10_000_000))); + try { + Query query = new Query("testLayer"); + int resolution = calculator.getTargetResolution(query, 1); + assertEquals(2, resolution); + } finally { + EnvFunction.clearLocalValues(); + } + } } diff --git a/src/community/ogcapi/dggs/web-dggs/src/main/java/org/geoserver/web/publish/dggs/DGGSConfigPanel.html b/src/community/ogcapi/dggs/web-dggs/src/main/java/org/geoserver/web/publish/dggs/DGGSConfigPanel.html index e6b3c8c5569..95e601d5b73 100644 --- a/src/community/ogcapi/dggs/web-dggs/src/main/java/org/geoserver/web/publish/dggs/DGGSConfigPanel.html +++ b/src/community/ogcapi/dggs/web-dggs/src/main/java/org/geoserver/web/publish/dggs/DGGSConfigPanel.html @@ -12,7 +12,7 @@
  • - +
  • diff --git a/src/community/ogcapi/dggs/web-dggs/src/test/java/org/geoserver/dggs/DGGSIntegrationTest.java b/src/community/ogcapi/dggs/web-dggs/src/test/java/org/geoserver/dggs/DGGSIntegrationTest.java new file mode 100644 index 00000000000..b6864082a22 --- /dev/null +++ b/src/community/ogcapi/dggs/web-dggs/src/test/java/org/geoserver/dggs/DGGSIntegrationTest.java @@ -0,0 +1,77 @@ +/* (c) 2024 Open Source Geospatial Foundation - all rights reserved + * This code is licensed under the GPL 2.0 license, available at the root + * application directory. + */ + +package org.geoserver.dggs; + +import static org.junit.Assert.assertEquals; + +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.geoserver.catalog.Catalog; +import org.geoserver.catalog.CatalogBuilder; +import org.geoserver.catalog.DataStoreInfo; +import org.geoserver.catalog.FeatureTypeInfo; +import org.geoserver.catalog.LayerInfo; +import org.geoserver.data.test.SystemTestData; +import org.geoserver.test.GeoServerSystemTestSupport; +import org.geotools.dggs.gstore.DGGSGeometryStoreFactory; +import org.geotools.dggs.gstore.DGGSResolutionCalculator; +import org.geotools.feature.NameImpl; +import org.junit.Test; + +public class DGGSIntegrationTest extends GeoServerSystemTestSupport { + + public static final String TYPENAME = "h3-geometry"; + + @Override + protected void onSetUp(SystemTestData testData) throws Exception { + super.onSetUp(testData); + + Catalog catalog = getCatalog(); + CatalogBuilder cb = new CatalogBuilder(catalog); + DataStoreInfo ds = cb.buildDataStore("h3"); + ds.getConnectionParameters().put(DGGSGeometryStoreFactory.DGGS_FACTORY_ID.key, "H3"); + catalog.add(ds); + + cb.setStore(ds); + FeatureTypeInfo ft = + cb.buildFeatureType(new NameImpl(catalog.getDefaultNamespace().getURI(), "H3")); + // alternative name, will ensure a retype feature source is used + ft.setName(TYPENAME); + // set the min/max resolutions as strings (that's how they are stored anyways) + ft.getMetadata().put(DGGSResolutionCalculator.CONFIGURED_MINRES_KEY, "0"); + ft.getMetadata().put(DGGSResolutionCalculator.CONFIGURED_MAXRES_KEY, "3"); + catalog.add(ft); + + LayerInfo layer = cb.buildLayer(ft); + catalog.add(layer); + } + + /** + * Does an end to end test of the DGGS extension, by querying the WMS service for the layer + * created in the setup, with a different name (to test the retype feature source) and with + * resolution settings configured as string. + */ + @Test + public void testGetFeatureInfo() throws Exception { + String url = + "wms?service=WMS&version=1.1.0&request=GetFeatureInfo&layers=" + + TYPENAME + + "&styles=&bbox=-180.0,-90.0,180.0,90.0&width=200&height=100&srs=EPSG:4326&format=image/png&info_format=application/json&query_layers=" + + TYPENAME + + "&x=100&y=50"; + JSONObject json = (JSONObject) getAsJSON(url); + print(json); + assertEquals("FeatureCollection", json.getString("type")); + JSONArray features = json.getJSONArray("features"); + assertEquals(1, features.size()); + JSONObject feature = features.getJSONObject(0); + assertEquals("Feature", feature.getString("type")); + JSONObject properties = feature.getJSONObject("properties"); + assertEquals("0", properties.getString("resolution")); + assertEquals("8083fffffffffff", properties.getString("zoneId")); + assertEquals("hexagon", properties.getString("shape")); + } +}