From 1fc498af785ae87792eff2eb7cc212752b4f9e51 Mon Sep 17 00:00:00 2001 From: rng Date: Mon, 3 Nov 2025 10:12:15 +1100 Subject: [PATCH 01/11] update comment and include more fields in LayerInfo --- .../server/core/model/ogc/wms/LayerInfo.java | 107 ++++++++++++++++++ .../server/core/service/wfs/WfsServer.java | 1 - .../server/core/service/wms/WmsServer.java | 19 +++- 3 files changed, 121 insertions(+), 6 deletions(-) diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/LayerInfo.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/LayerInfo.java index 7e829e9f..d2456c2d 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/LayerInfo.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/LayerInfo.java @@ -1,20 +1,127 @@ package au.org.aodn.ogcapi.server.core.model.ogc.wms; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import java.util.List; + @Data @Builder @NoArgsConstructor @AllArgsConstructor +@JacksonXmlRootElement(localName = "Layer") public class LayerInfo { + @JacksonXmlProperty(isAttribute = true) + private String queryable; + + @JacksonXmlProperty(isAttribute = true) + private String opaque; + @JacksonXmlProperty(localName = "Name") protected String name; @JacksonXmlProperty(localName = "Title") protected String title; + + @JacksonXmlProperty(localName = "Abstract") + private String abstract_; + + @JacksonXmlProperty(localName = "KeywordList") + private KeywordList keywordList; + + @JacksonXmlElementWrapper(useWrapping = false) + @JacksonXmlProperty(localName = "CRS") + private List crs; + + @JacksonXmlProperty(localName = "EX_GeographicBoundingBox") + private GeographicBoundingBox geographicBoundingBox; + + @JacksonXmlElementWrapper(useWrapping = false) + @JacksonXmlProperty(localName = "BoundingBox") + private List boundingBoxes; + + @JacksonXmlProperty(localName = "Style") + private Style style; } + +class KeywordList { + @JacksonXmlElementWrapper(useWrapping = false) + @JacksonXmlProperty(localName = "Keyword") + private List keyword; +} + +class GeographicBoundingBox { + @JacksonXmlProperty(localName = "westBoundLongitude") + private double westBoundLongitude; + + @JacksonXmlProperty(localName = "eastBoundLongitude") + private double eastBoundLongitude; + + @JacksonXmlProperty(localName = "southBoundLatitude") + private double southBoundLatitude; + + @JacksonXmlProperty(localName = "northBoundLatitude") + private double northBoundLatitude; +} + +class BoundingBox { + @JacksonXmlProperty(isAttribute = true) + private String CRS; + + @JacksonXmlProperty(isAttribute = true) + private double minx; + + @JacksonXmlProperty(isAttribute = true) + private double miny; + + @JacksonXmlProperty(isAttribute = true) + private double maxx; + + @JacksonXmlProperty(isAttribute = true) + private double maxy; +} + +class Style { + @JacksonXmlProperty(localName = "Name") + private String name; + + @JacksonXmlProperty(localName = "Title") + private String title; + + @JacksonXmlProperty(localName = "Abstract") + private String abstract_; + + @JacksonXmlProperty(localName = "LegendURL") + private LegendURL legendURL; +} + +class LegendURL { + @JacksonXmlProperty(isAttribute = true) + private int width; + + @JacksonXmlProperty(isAttribute = true) + private int height; + + @JacksonXmlProperty(localName = "Format") + private String format; + + @JacksonXmlProperty(localName = "OnlineResource") + private OnlineResource onlineResource; +} + +class OnlineResource { + @JacksonXmlProperty(isAttribute = true, localName = "xlink", namespace = "http://www.w3.org/2000/xmlns/") + private String xlink; + + @JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/1999/xlink") + private String type; + + @JacksonXmlProperty(isAttribute = true, localName = "href", namespace = "http://www.w3.org/1999/xlink") + private String href; +} \ No newline at end of file diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java index b5ba90e6..f76eb320 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java @@ -193,7 +193,6 @@ protected Optional extractTypenameFromUrl(String url) { } return Optional.empty(); } - /** * Filter WMS layers based on matching with WFS links * Matching logic: diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServer.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServer.java index ab6e22d9..910c8929 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServer.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServer.java @@ -112,7 +112,13 @@ protected String createCQLFilter(String uuid, FeatureRequest request) { } return ""; } - + /** + * Create the full WMS url to fetch the tiles image + * @param url - The url from the metadata, it may point to the wms server only without specifying the remain details, this function will do a smart lookup + * @param uuid - The UUID of the metadata which use to find the WFS links + * @param request - The request like bbox and other param say datetime, layerName (where layerName is not reliable and need lookup internally) + * @return - The final URl to do the query + */ protected List createMapQueryUrl(String url, String uuid, FeatureRequest request) { try { UriComponents components = UriComponentsBuilder.fromUriString(url).build(); @@ -452,7 +458,12 @@ public byte[] getMapTile(String collectionId, FeatureRequest request) throws URI } return null; } - + /** + * Query the field using WMS's DescriberLayer function to find out the associated WFS layer and fields + * @param collectionId - The uuid of the metadata that hold this WMS link + * @param request - Request item for this WMS layer, usually layer name, size, etc. + * @return - The fields contained in this WMS layer, we are particular interest in the date time field for subsetting + */ public List getDownloadableFields(String collectionId, FeatureRequest request) { DescribeLayerResponse response = this.describeLayer(collectionId, request); @@ -465,9 +476,8 @@ public List getDownloadableFields(String collectionId, F return wfsServer.getDownloadableFields(collectionId, request, null); } } - /** - * Fetch raw layers from WMS GetCapabilities - cached by URL + * Fetch raw layers from WMS GetCapabilities - cached by URL, that is query all layer supported by this WMS server. * This allows multiple collections sharing the same WMS server to use cached results * * @param wmsServerUrl - The WMS server base URL @@ -527,7 +537,6 @@ public List fetchCapabilitiesLayersByUrl(String wmsServerUrl) { return Collections.emptyList(); } - /** * Get filtered layers from WMS GetCapabilities for a specific collection * First fetches all layers (cached by URL), then filters by WFS links (cached by UUID) From f006ddeca895cba756d75ffa20b4c52fae4530de Mon Sep 17 00:00:00 2001 From: rng Date: Mon, 3 Nov 2025 17:02:27 +1100 Subject: [PATCH 02/11] Minor refactor --- .../au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java index f76eb320..23d38d56 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java @@ -129,7 +129,7 @@ protected Optional> getAllFeatureServerUrls(String collectionId) { * @param layerName - The layer name to match the title * @return - The first wfs server link if found */ - protected Optional getFeatureServerUrl(String collectionId, String layerName) { + public Optional getFeatureServerUrl(String collectionId, String layerName) { ElasticSearchBase.SearchResult result = search.searchCollections(collectionId); if (!result.getCollections().isEmpty()) { StacCollectionModel model = result.getCollections().get(0); From a06b37e1dd30f1154bfa8821109731cccb8a7f6a Mon Sep 17 00:00:00 2001 From: rng Date: Mon, 3 Nov 2025 19:57:15 +1100 Subject: [PATCH 03/11] Fix issue with using class --- .../core/model/ogc/wms/BoundingBox.java | 28 +++++++ .../model/ogc/wms/GeographicBoundingBox.java | 25 ++++++ .../core/model/ogc/wms/KeywordList.java | 20 +++++ .../server/core/model/ogc/wms/LayerInfo.java | 76 ------------------- .../server/core/model/ogc/wms/LegendURL.java | 25 ++++++ .../core/model/ogc/wms/OnlineResource.java | 22 ++++++ .../server/core/model/ogc/wms/Style.java | 25 ++++++ .../server/core/service/wms/WmsServer.java | 3 +- 8 files changed, 146 insertions(+), 78 deletions(-) create mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/BoundingBox.java create mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/GeographicBoundingBox.java create mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/KeywordList.java create mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/LegendURL.java create mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/OnlineResource.java create mode 100644 server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/Style.java diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/BoundingBox.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/BoundingBox.java new file mode 100644 index 00000000..873fea22 --- /dev/null +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/BoundingBox.java @@ -0,0 +1,28 @@ +package au.org.aodn.ogcapi.server.core.model.ogc.wms; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BoundingBox { + @JacksonXmlProperty(isAttribute = true) + private String CRS; + + @JacksonXmlProperty(isAttribute = true) + private double minx; + + @JacksonXmlProperty(isAttribute = true) + private double miny; + + @JacksonXmlProperty(isAttribute = true) + private double maxx; + + @JacksonXmlProperty(isAttribute = true) + private double maxy; +} diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/GeographicBoundingBox.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/GeographicBoundingBox.java new file mode 100644 index 00000000..b2f29bf2 --- /dev/null +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/GeographicBoundingBox.java @@ -0,0 +1,25 @@ +package au.org.aodn.ogcapi.server.core.model.ogc.wms; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class GeographicBoundingBox { + @JacksonXmlProperty(localName = "westBoundLongitude") + private double westBoundLongitude; + + @JacksonXmlProperty(localName = "eastBoundLongitude") + private double eastBoundLongitude; + + @JacksonXmlProperty(localName = "southBoundLatitude") + private double southBoundLatitude; + + @JacksonXmlProperty(localName = "northBoundLatitude") + private double northBoundLatitude; +} diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/KeywordList.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/KeywordList.java new file mode 100644 index 00000000..05f4d0ff --- /dev/null +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/KeywordList.java @@ -0,0 +1,20 @@ +package au.org.aodn.ogcapi.server.core.model.ogc.wms; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class KeywordList { + @JacksonXmlElementWrapper(useWrapping = false) + @JacksonXmlProperty(localName = "Keyword") + private List keyword; +} diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/LayerInfo.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/LayerInfo.java index d2456c2d..34d996c9 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/LayerInfo.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/LayerInfo.java @@ -49,79 +49,3 @@ public class LayerInfo { @JacksonXmlProperty(localName = "Style") private Style style; } - -class KeywordList { - @JacksonXmlElementWrapper(useWrapping = false) - @JacksonXmlProperty(localName = "Keyword") - private List keyword; -} - -class GeographicBoundingBox { - @JacksonXmlProperty(localName = "westBoundLongitude") - private double westBoundLongitude; - - @JacksonXmlProperty(localName = "eastBoundLongitude") - private double eastBoundLongitude; - - @JacksonXmlProperty(localName = "southBoundLatitude") - private double southBoundLatitude; - - @JacksonXmlProperty(localName = "northBoundLatitude") - private double northBoundLatitude; -} - -class BoundingBox { - @JacksonXmlProperty(isAttribute = true) - private String CRS; - - @JacksonXmlProperty(isAttribute = true) - private double minx; - - @JacksonXmlProperty(isAttribute = true) - private double miny; - - @JacksonXmlProperty(isAttribute = true) - private double maxx; - - @JacksonXmlProperty(isAttribute = true) - private double maxy; -} - -class Style { - @JacksonXmlProperty(localName = "Name") - private String name; - - @JacksonXmlProperty(localName = "Title") - private String title; - - @JacksonXmlProperty(localName = "Abstract") - private String abstract_; - - @JacksonXmlProperty(localName = "LegendURL") - private LegendURL legendURL; -} - -class LegendURL { - @JacksonXmlProperty(isAttribute = true) - private int width; - - @JacksonXmlProperty(isAttribute = true) - private int height; - - @JacksonXmlProperty(localName = "Format") - private String format; - - @JacksonXmlProperty(localName = "OnlineResource") - private OnlineResource onlineResource; -} - -class OnlineResource { - @JacksonXmlProperty(isAttribute = true, localName = "xlink", namespace = "http://www.w3.org/2000/xmlns/") - private String xlink; - - @JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/1999/xlink") - private String type; - - @JacksonXmlProperty(isAttribute = true, localName = "href", namespace = "http://www.w3.org/1999/xlink") - private String href; -} \ No newline at end of file diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/LegendURL.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/LegendURL.java new file mode 100644 index 00000000..349b7fad --- /dev/null +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/LegendURL.java @@ -0,0 +1,25 @@ +package au.org.aodn.ogcapi.server.core.model.ogc.wms; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class LegendURL { + @JacksonXmlProperty(isAttribute = true) + private int width; + + @JacksonXmlProperty(isAttribute = true) + private int height; + + @JacksonXmlProperty(localName = "Format") + private String format; + + @JacksonXmlProperty(localName = "OnlineResource") + private OnlineResource onlineResource; +} diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/OnlineResource.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/OnlineResource.java new file mode 100644 index 00000000..2cda6877 --- /dev/null +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/OnlineResource.java @@ -0,0 +1,22 @@ +package au.org.aodn.ogcapi.server.core.model.ogc.wms; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OnlineResource { + @JacksonXmlProperty(isAttribute = true, localName = "xlink", namespace = "http://www.w3.org/2000/xmlns/") + private String xlink; + + @JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/1999/xlink") + private String type; + + @JacksonXmlProperty(isAttribute = true, localName = "href", namespace = "http://www.w3.org/1999/xlink") + private String href; +} diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/Style.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/Style.java new file mode 100644 index 00000000..5cbd05e0 --- /dev/null +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/model/ogc/wms/Style.java @@ -0,0 +1,25 @@ +package au.org.aodn.ogcapi.server.core.model.ogc.wms; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Style { + @JacksonXmlProperty(localName = "Name") + private String name; + + @JacksonXmlProperty(localName = "Title") + private String title; + + @JacksonXmlProperty(localName = "Abstract") + private String abstract_; + + @JacksonXmlProperty(localName = "LegendURL") + private LegendURL legendURL; +} diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServer.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServer.java index 910c8929..883dc761 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServer.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServer.java @@ -352,7 +352,7 @@ protected Optional getMapServerUrl(String collectionId, FeatureRequest r return Optional.empty(); } - Optional matchedUrl = Optional.empty(); + Optional matchedUrl; if (layerName != null && !layerName.isEmpty()) { // If layer name provided, try to match by layer name @@ -426,7 +426,6 @@ public DescribeLayerResponse describeLayer(String collectionId, FeatureRequest r } } catch (RestClientException | URISyntaxException | JsonProcessingException pe) { log.debug("Exception ignored it as we will retry", pe); - throw new RuntimeException(pe); } } } From df31ea0edb8c6b528ec9f36bccc140d76237742e Mon Sep 17 00:00:00 2001 From: rng Date: Mon, 3 Nov 2025 21:23:30 +1100 Subject: [PATCH 04/11] Added CQL --- .../service/wfs/DownloadWfsDataService.java | 2 +- .../server/core/service/wfs/WfsServer.java | 30 +++++++++++++++++-- .../server/core/service/wms/WmsServer.java | 24 +++++++++++---- .../wfs/DownloadWfsDataServiceTest.java | 10 +++---- 4 files changed, 50 insertions(+), 16 deletions(-) diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadWfsDataService.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadWfsDataService.java index 1f32c405..02343ec1 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadWfsDataService.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadWfsDataService.java @@ -136,7 +136,7 @@ public String prepareWfsRequestUrl( downloadableFields = wfsServer.getDownloadableFields(uuid, FeatureRequest.builder().layerName(wfsTypeName).build(), wfsServerUrl); log.info("DownloadableFields by describeLayer: {}", downloadableFields); } else { - Optional featureServerUrl = wfsServer.getFeatureServerUrl(uuid, layerName); + Optional featureServerUrl = wfsServer.getFeatureServerUrlByTitle(uuid, layerName); if (featureServerUrl.isPresent()) { wfsServerUrl = featureServerUrl.get(); diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java index 23d38d56..63cf033b 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java @@ -121,7 +121,6 @@ protected Optional> getAllFeatureServerUrls(String collectionId) { return Optional.empty(); } } - /** * Find the url that is able to get WFS call, this can be found in ai:Group * @@ -129,7 +128,7 @@ protected Optional> getAllFeatureServerUrls(String collectionId) { * @param layerName - The layer name to match the title * @return - The first wfs server link if found */ - public Optional getFeatureServerUrl(String collectionId, String layerName) { + public Optional getFeatureServerUrlByTitle(String collectionId, String layerName) { ElasticSearchBase.SearchResult result = search.searchCollections(collectionId); if (!result.getCollections().isEmpty()) { StacCollectionModel model = result.getCollections().get(0); @@ -143,7 +142,32 @@ public Optional getFeatureServerUrl(String collectionId, String layerNam return Optional.empty(); } } - + /** + * Find the url that is able to get WFS call, this can be found in ai:Group + * + * @param collectionId - The uuid + * @param layerName - The layer name to match the title + * @return - The first wfs server link if found + */ + public Optional getFeatureServerUrlByTitleOrQueryParam(String collectionId, String layerName) { + ElasticSearchBase.SearchResult result = search.searchCollections(collectionId); + if (!result.getCollections().isEmpty()) { + StacCollectionModel model = result.getCollections().get(0); + return model.getLinks() + .stream() + .filter(link -> link.getAiGroup() != null) + .filter(link -> link.getAiGroup().contains("Data Access > wfs")) + .filter(link -> { + Optional name = extractTypenameFromUrl(link.getHref()); + return link.getTitle().equalsIgnoreCase(layerName) || + (name.isPresent() && fuzzyMatch(name.get(), layerName)); + }) + .map(LinkModel::getHref) + .findFirst(); + } else { + return Optional.empty(); + } + } /** * Fuzzy match utility to compare layer names, ignoring namespace prefixes * For example: "underway:nuyina_underway_202122020" matches "nuyina_underway_202122020" diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServer.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServer.java index 883dc761..23186e30 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServer.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServer.java @@ -70,9 +70,20 @@ protected String createCQLFilter(String uuid, FeatureRequest request) { if (request.getDatetime() != null) { // Special handle for date time field, the field name will be diff across dataset. So we need // to look it up - String cql = null; - + String cql = ""; try { + Optional wfsUrl = wfsServer.getFeatureServerUrlByTitleOrQueryParam(uuid, request.getLayerName()); + if(wfsUrl.isPresent()) { + UriComponents wfsUrlComponents = UriComponentsBuilder.fromUriString(wfsUrl.get()).build(); + // Extract the CQL if existing in the WFS, we need to apply it to the WMS as well + if(wfsUrlComponents.getQueryParams().get("cql_filter") != null) { + cql = wfsUrlComponents.getQueryParams().get("cql_filter").get(0) + " AND "; + } + else if(wfsUrlComponents.getQueryParams().get("CQL_FILTER") != null) { + cql = wfsUrlComponents.getQueryParams().get("CQL_FILTER").get(0) + " AND "; + } + } + List m = this.getDownloadableFields(uuid, request); List target = m.stream() .filter(value -> "dateTime".equalsIgnoreCase(value.getType())) @@ -93,15 +104,15 @@ protected String createCQLFilter(String uuid, FeatureRequest request) { String guess1 = target.get(0).getName(); String guess2 = target.get(1).getName(); if ((guess1.contains("start") || guess1.contains("min")) && (guess2.contains("end") || guess2.contains("max"))) { - return String.format("CQL_FILTER=%s >= %s AND %s <= %s", guess1, d[0], guess2, d[1]); + return String.format("CQL_FILTER=%s%s >= %s AND %s <= %s", cql, guess1, d[0], guess2, d[1]); } if ((guess2.contains("start") || guess2.contains("min")) && (guess1.contains("end") || guess1.contains("max"))) { - return String.format("CQL_FILTER=%s >= %s AND %s <= %s", guess2, d[0], guess2, d[1]); + return String.format("CQL_FILTER=%s%s >= %s AND %s <= %s", cql, guess2, d[0], guess2, d[1]); } } else { // Only 1 field so use it. log.debug("Map datetime field to name to [{}]", target.get(0).getName()); - return String.format("CQL_FILTER=%s DURING %s", target.get(0).getName(), request.getDatetime()); + return String.format("CQL_FILTER=%s%s DURING %s", cql, target.get(0).getName(), request.getDatetime()); } } log.error("No date time field found from query for uuid {}, result will not be bounded by date time", uuid); @@ -163,7 +174,7 @@ protected List createMapQueryUrl(String url, String uuid, FeatureRequest // This is the normal route UriComponentsBuilder builder = UriComponentsBuilder .newInstance() - .scheme(components.getScheme()) + .scheme("https") .port(components.getPort()) .host(components.getHost()) .path(components.getPath()); @@ -426,6 +437,7 @@ public DescribeLayerResponse describeLayer(String collectionId, FeatureRequest r } } catch (RestClientException | URISyntaxException | JsonProcessingException pe) { log.debug("Exception ignored it as we will retry", pe); + throw new RuntimeException(pe); } } } diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadWfsDataServiceTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadWfsDataServiceTest.java index b444c1bd..1d848e44 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadWfsDataServiceTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadWfsDataServiceTest.java @@ -270,14 +270,12 @@ public void testPrepareWfsRequestUrl_NoWfsServerUrl() { String layerName = "test:layer"; when(wmsServer.describeLayer(eq(uuid), any(FeatureRequest.class))).thenReturn(null); - when(wfsServer.getFeatureServerUrl(eq(uuid), eq(layerName))).thenReturn(java.util.Optional.empty()); + when(wfsServer.getFeatureServerUrlByTitle(eq(uuid), eq(layerName))).thenReturn(java.util.Optional.empty()); // Test with no WFS server URL available - Exception exception = assertThrows(IllegalArgumentException.class, () -> { - downloadWfsDataService.prepareWfsRequestUrl( - uuid, null, null, null, null, layerName - ); - }); + Exception exception = assertThrows(IllegalArgumentException.class, () -> downloadWfsDataService.prepareWfsRequestUrl( + uuid, null, null, null, null, layerName + )); assertTrue(exception.getMessage().contains("No WFS server URL found")); } From ee133c25e784b3d79b45f7cf4ed907aa48d7ae1b Mon Sep 17 00:00:00 2001 From: rng Date: Tue, 4 Nov 2025 11:52:56 +1100 Subject: [PATCH 05/11] Prefer aodn_map layer --- .../server/core/service/wfs/WfsServer.java | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java index 63cf033b..b4b1c226 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java @@ -160,7 +160,7 @@ public Optional getFeatureServerUrlByTitleOrQueryParam(String collection .filter(link -> { Optional name = extractTypenameFromUrl(link.getHref()); return link.getTitle().equalsIgnoreCase(layerName) || - (name.isPresent() && fuzzyMatch(name.get(), layerName)); + (name.isPresent() && roughlyMatch(name.get(), layerName)); }) .map(LinkModel::getHref) .findFirst(); @@ -176,7 +176,7 @@ public Optional getFeatureServerUrlByTitleOrQueryParam(String collection * @param text2 - Second text to compare * @return true if texts match (after removing namespace prefix) */ - protected boolean fuzzyMatch(String text1, String text2) { + protected boolean roughlyMatch(String text1, String text2) { if (text1 == null || text2 == null) { return false; } @@ -185,9 +185,14 @@ protected boolean fuzzyMatch(String text1, String text2) { String normalized1 = text1.contains(":") ? text1.substring(text1.indexOf(":") + 1) : text1; String normalized2 = text2.contains(":") ? text2.substring(text2.indexOf(":") + 1) : text2; - return normalized1.equalsIgnoreCase(normalized2); + if (normalized1.length() < normalized2.length()) { + // Swap the text so that compare startsWith using longer text. + String temp = normalized1; + normalized1 = normalized2; + normalized2 = temp; + } + return normalized1.startsWith(normalized2); } - /** * Extract typename from WFS URL query parameters * @@ -259,21 +264,21 @@ public List filterLayersByWfsLinks(String collectionId, List typename = extractTypenameFromUrl(wfsLink.getHref()); if (typename.isPresent()) { - if (fuzzyMatch(typename.get(), layer.getName()) || - fuzzyMatch(typename.get(), layer.getTitle())) { + if (roughlyMatch(typename.get(), layer.getName()) || + roughlyMatch(typename.get(), layer.getTitle())) { log.debug(" ✓ Fallback match found - typename '{}' matches layer '{}'", typename.get(), layer.getName()); matched = true; @@ -288,6 +293,13 @@ public List filterLayersByWfsLinks(String collectionId, List aodn_map = filteredLayers.stream().filter(l -> l.getName().endsWith("_aodn_map")).toList(); + if(!aodn_map.isEmpty()) { + filteredLayers = aodn_map; + } + log.info("Filtered {} layers out of {} based on WFS link matching", filteredLayers.size(), layers.size()); return filteredLayers; From 762ffa0ebd6ed6c92af099fdcf0e35e78424f9e2 Mon Sep 17 00:00:00 2001 From: rng Date: Tue, 4 Nov 2025 13:09:56 +1100 Subject: [PATCH 06/11] Add test case --- .../core/configuration/WfsWmsConfig.java | 11 +++- .../server/core/service/wfs/WfsServer.java | 25 ++++---- .../server/service/wfs/WfsServerTest.java | 60 +++++++++++++++++++ 3 files changed, 82 insertions(+), 14 deletions(-) create mode 100644 server/src/test/java/au/org/aodn/ogcapi/server/service/wfs/WfsServerTest.java diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/configuration/WfsWmsConfig.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/configuration/WfsWmsConfig.java index ed61437a..9bbfdf87 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/configuration/WfsWmsConfig.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/configuration/WfsWmsConfig.java @@ -1,16 +1,23 @@ package au.org.aodn.ogcapi.server.core.configuration; +import au.org.aodn.ogcapi.server.core.service.Search; +import au.org.aodn.ogcapi.server.core.service.wfs.DownloadableFieldsService; import au.org.aodn.ogcapi.server.core.service.wfs.WfsServer; import au.org.aodn.ogcapi.server.core.service.wms.WmsServer; +import au.org.aodn.ogcapi.server.core.util.RestTemplateUtils; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; @Configuration public class WfsWmsConfig { @Bean - public WfsServer createWfsServer() { - return new WfsServer(); + public WfsServer createWfsServer(Search search, + DownloadableFieldsService downloadableFieldsService, + RestTemplate restTemplate, + RestTemplateUtils restTemplateUtils) { + return new WfsServer(search, downloadableFieldsService, restTemplate, restTemplateUtils); } @Bean diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java index b4b1c226..fcbf0d8a 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java @@ -15,7 +15,6 @@ import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestClientException; @@ -26,6 +25,7 @@ import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Optional; import static au.org.aodn.ogcapi.server.core.configuration.CacheConfig.DOWNLOADABLE_FIELDS; @@ -34,23 +34,24 @@ public class WfsServer { // Cannot use singleton bean as it impacted other dependency protected final XmlMapper xmlMapper; - - @Autowired protected DownloadableFieldsService downloadableFieldsService; - - @Autowired protected RestTemplateUtils restTemplateUtils; - - @Autowired protected RestTemplate restTemplate; - - @Autowired protected Search search; - public WfsServer() { + public WfsServer(Search search, + DownloadableFieldsService downloadableFieldsService, + RestTemplate restTemplate, + RestTemplateUtils restTemplateUtils) { + xmlMapper = new XmlMapper(); xmlMapper.registerModule(new JavaTimeModule()); // Add JavaTimeModule xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + this.search = search; + this.restTemplate = restTemplate; + this.restTemplateUtils = restTemplateUtils; + this.downloadableFieldsService = downloadableFieldsService; } /** @@ -237,7 +238,7 @@ public List filterLayersByWfsLinks(String collectionId, List filterLayersByWfsLinks(String collectionId, List result = new ElasticSearchBase.SearchResult<>(); + result.setCollections(Collections.emptyList()); + when(mockSearch.searchCollections(anyString())).thenReturn(result); + + WfsServer server = new WfsServer(mockSearch, downloadableFieldsService, restTemplate, new RestTemplateUtils(restTemplate)); + + List layers = Collections.singletonList(LayerInfo.builder().build()); + assertEquals(Collections.emptyList(), server.filterLayersByWfsLinks("id", layers)); + } + + @Test + void noWfsLinks_returnsEmptyLayers() { + Search mockSearch = mock(Search.class); + DownloadableFieldsService downloadableFieldsService = mock(DownloadableFieldsService.class); + RestTemplate restTemplate = mock(RestTemplate.class); + + StacCollectionModel model = mock(StacCollectionModel.class); + when(model.getLinks()).thenReturn(Collections.emptyList()); + + ElasticSearchBase.SearchResult result = new ElasticSearchBase.SearchResult<>(); + result.setCollections(List.of(model)); + + when(mockSearch.searchCollections(anyString())).thenReturn(result); + + WfsServer server = new WfsServer(mockSearch, downloadableFieldsService, restTemplate, new RestTemplateUtils(restTemplate)); + + List layers = Collections.singletonList(LayerInfo.builder().build()); + assertEquals(Collections.emptyList(), server.filterLayersByWfsLinks("id", layers)); + } +} From 10a6e77e5a4bde2df76bd015e3a61abd09950807 Mon Sep 17 00:00:00 2001 From: rng Date: Tue, 4 Nov 2025 13:33:45 +1100 Subject: [PATCH 07/11] Add 1 test case --- .../server/service/wfs/WfsServerTest.java | 60 ++++++++++++++++--- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/service/wfs/WfsServerTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/service/wfs/WfsServerTest.java index bf8d432f..8d0edd53 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/service/wfs/WfsServerTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/service/wfs/WfsServerTest.java @@ -1,5 +1,6 @@ package au.org.aodn.ogcapi.server.service.wfs; +import au.org.aodn.ogcapi.server.core.model.LinkModel; import au.org.aodn.ogcapi.server.core.model.StacCollectionModel; import au.org.aodn.ogcapi.server.core.model.ogc.wms.LayerInfo; import au.org.aodn.ogcapi.server.core.service.ElasticSearchBase; @@ -7,7 +8,11 @@ import au.org.aodn.ogcapi.server.core.service.wfs.DownloadableFieldsService; import au.org.aodn.ogcapi.server.core.service.wfs.WfsServer; import au.org.aodn.ogcapi.server.core.util.RestTemplateUtils; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.springframework.web.client.RestTemplate; import java.util.Collections; @@ -19,15 +24,32 @@ import static org.mockito.Mockito.when; public class WfsServerTest { + + @Mock + Search mockSearch; + + @Mock + DownloadableFieldsService downloadableFieldsService; + + @Mock + RestTemplate restTemplate; + + AutoCloseable closeableMock; + + @BeforeEach + public void setUp() { + closeableMock = MockitoAnnotations.openMocks(this); + } + + @AfterEach + void cleanUp() throws Exception { + closeableMock.close(); + } /** * Test null case where the dataset have the collection id not found */ @Test void noCollection_returnsEmptyLayers() { - Search mockSearch = mock(Search.class); - DownloadableFieldsService downloadableFieldsService = mock(DownloadableFieldsService.class); - RestTemplate restTemplate = mock(RestTemplate.class); - ElasticSearchBase.SearchResult result = new ElasticSearchBase.SearchResult<>(); result.setCollections(Collections.emptyList()); when(mockSearch.searchCollections(anyString())).thenReturn(result); @@ -40,10 +62,6 @@ void noCollection_returnsEmptyLayers() { @Test void noWfsLinks_returnsEmptyLayers() { - Search mockSearch = mock(Search.class); - DownloadableFieldsService downloadableFieldsService = mock(DownloadableFieldsService.class); - RestTemplate restTemplate = mock(RestTemplate.class); - StacCollectionModel model = mock(StacCollectionModel.class); when(model.getLinks()).thenReturn(Collections.emptyList()); @@ -57,4 +75,30 @@ void noWfsLinks_returnsEmptyLayers() { List layers = Collections.singletonList(LayerInfo.builder().build()); assertEquals(Collections.emptyList(), server.filterLayersByWfsLinks("id", layers)); } + /** + * The function should fine one because title name matches + */ + @Test + void primaryTitleMatch_filtersMatchingLayers() { + LinkModel wfsLink = LinkModel.builder() + .title("test_layer") + .aiGroup("Data Access > wfs") + .href("http://example.com?wfs").build(); + + StacCollectionModel model = StacCollectionModel.builder().links(List.of(wfsLink)).build(); + var layers = List.of( + LayerInfo.builder().title("test_layer").name("").build(), + LayerInfo.builder().title("other").build() + ); + + ElasticSearchBase.SearchResult result = new ElasticSearchBase.SearchResult<>(); + result.setCollections(List.of(model)); + when(mockSearch.searchCollections(anyString())).thenReturn(result); + + WfsServer server = new WfsServer(mockSearch, downloadableFieldsService, restTemplate, new RestTemplateUtils(restTemplate)); + + List info = server.filterLayersByWfsLinks("id", layers); + assertEquals(1, info.size(), "Layer match"); + assertEquals(layers.get(0), info.get(0), "Layer test_layer found"); + } } From 464fe071f6c28853af94250a080e5ceb068aadc4 Mon Sep 17 00:00:00 2001 From: rng Date: Tue, 4 Nov 2025 13:40:54 +1100 Subject: [PATCH 08/11] Add more test case --- .../server/core/service/wfs/WfsServer.java | 4 ++- .../server/service/wfs/WfsServerTest.java | 30 ++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java index fcbf0d8a..6bbb3188 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java @@ -296,7 +296,9 @@ public List filterLayersByWfsLinks(String collectionId, List aodn_map = filteredLayers.stream().filter(l -> l.getName().endsWith("_aodn_map")).toList(); + List aodn_map = filteredLayers.stream().filter(l -> + l.getName().endsWith("_aodn_map") || l.getTitle().endsWith("_aodn_map") + ).toList(); if(!aodn_map.isEmpty()) { filteredLayers = aodn_map; } diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/service/wfs/WfsServerTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/service/wfs/WfsServerTest.java index 8d0edd53..58cac516 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/service/wfs/WfsServerTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/service/wfs/WfsServerTest.java @@ -98,7 +98,35 @@ void primaryTitleMatch_filtersMatchingLayers() { WfsServer server = new WfsServer(mockSearch, downloadableFieldsService, restTemplate, new RestTemplateUtils(restTemplate)); List info = server.filterLayersByWfsLinks("id", layers); - assertEquals(1, info.size(), "Layer match"); + assertEquals(1, info.size(), "Layer count match"); assertEquals(layers.get(0), info.get(0), "Layer test_layer found"); } + /** + * The function will scan the layer that match if there exist layers where name ends with _aodn_map, then + * only return those, otherwise return layers found without _aodn_map sufix. This make the portal works like + * old portal where they setup layer for portal with sufix _aodn_map + */ + @Test + void primaryTitleMatch_filtersPreferAodnMapLayers() { + LinkModel wfsLink = LinkModel.builder() + .title("test_layer") + .aiGroup("Data Access > wfs") + .href("http://example.com?wfs").build(); + + StacCollectionModel model = StacCollectionModel.builder().links(List.of(wfsLink)).build(); + var layers = List.of( + LayerInfo.builder().title("test_layer").name("").build(), + LayerInfo.builder().title("layer:test_layer_aodn_map").name("").build() + ); + + ElasticSearchBase.SearchResult result = new ElasticSearchBase.SearchResult<>(); + result.setCollections(List.of(model)); + when(mockSearch.searchCollections(anyString())).thenReturn(result); + + WfsServer server = new WfsServer(mockSearch, downloadableFieldsService, restTemplate, new RestTemplateUtils(restTemplate)); + + List info = server.filterLayersByWfsLinks("id", layers); + assertEquals(1, info.size(), "Layer count match"); + assertEquals(layers.get(1), info.get(0), "Layer layer:test_layer_aodn_map found"); + } } From ace14d55a2b5ae64a5a505d02559ec37cd28b54c Mon Sep 17 00:00:00 2001 From: rng Date: Tue, 4 Nov 2025 13:55:22 +1100 Subject: [PATCH 09/11] Fix test --- .../au/org/aodn/ogcapi/server/core/util/ConstructUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/util/ConstructUtils.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/util/ConstructUtils.java index 475036a7..f4059c5e 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/util/ConstructUtils.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/util/ConstructUtils.java @@ -10,7 +10,7 @@ public class ConstructUtils { @Setter - private static ObjectMapper objectMapper; + private static ObjectMapper objectMapper = new ObjectMapper(); // Give default public static Optional constructByJsonString(String jsonString, Class clazz) { try { From 56176bc176bc84d515734dc1d9d9b5f7a5df2b2b Mon Sep 17 00:00:00 2001 From: rng Date: Wed, 5 Nov 2025 10:18:28 +1100 Subject: [PATCH 10/11] Minor tune --- server/pom.xml | 4 ++++ .../aodn/ogcapi/server/core/configuration/CacheConfig.java | 2 +- .../au/org/aodn/ogcapi/server/core/service/CacheWarm.java | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/server/pom.xml b/server/pom.xml index c332c1b1..7f5c80c9 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -76,6 +76,10 @@ javax.cache cache-api + + org.springframework.retry + spring-retry + org.mapstruct mapstruct diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/configuration/CacheConfig.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/configuration/CacheConfig.java index 25d82cc7..250da0c5 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/configuration/CacheConfig.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/configuration/CacheConfig.java @@ -81,7 +81,7 @@ public JCacheCacheManager cacheManager() throws IOException { CacheConfigurationBuilder.newCacheConfigurationBuilder( Object.class, Object.class, ResourcePoolsBuilder.heap(50) - ).withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofMinutes(5))) + ).withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(15))) ) .withCache(STRING_TO_GEOMETRY, CacheConfigurationBuilder.newCacheConfigurationBuilder( diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/CacheWarm.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/CacheWarm.java index 8dce97c5..30effbff 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/CacheWarm.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/CacheWarm.java @@ -19,7 +19,8 @@ public class CacheWarm { // Hardcode server list as not expect to change much overtime, add more if needed protected List getCapabilitiesUrls = List.of( - "https://data.aad.gov.au/geoserver/underway/wms" + "https://data.aad.gov.au/geoserver/underway/ows" + // "https://www.cmar.csiro.au/geoserver/ows" <- This one super slow and do not return complete XML, need a ticket to fix ); protected WmsServer wmsServer; protected GeometryUtils geometryUtils; From c0211e3cf8d2ed9f8953bce9cdfc861815a5ebcd Mon Sep 17 00:00:00 2001 From: rng Date: Wed, 5 Nov 2025 11:10:31 +1100 Subject: [PATCH 11/11] Update wordings --- .../au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java index 6bbb3188..e6429820 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/wfs/WfsServer.java @@ -237,7 +237,7 @@ public List filterLayersByWfsLinks(String collectionId, List result = search.searchCollections(collectionId); if (result.getCollections().isEmpty()) { - log.info("Return all layers if as no collection found for collectionId: {}", collectionId); + log.info("Return empty layers if as no collection found for collectionId: {}", collectionId); return Collections.emptyList(); } @@ -251,7 +251,7 @@ public List filterLayersByWfsLinks(String collectionId, List