Skip to content

Commit 1fef8bd

Browse files
authored
Merge branch 'main' into feature/7224-integrate-ai-downloadable-links
2 parents d9f3ab0 + 07ff981 commit 1fef8bd

5 files changed

Lines changed: 104 additions & 21 deletions

File tree

server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/WfsServer.java

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -217,11 +217,10 @@ protected List<LinkModel> getWfsLinks(String collectionId) {
217217

218218
StacCollectionModel model = result.getCollections().get(0);
219219

220-
// Filter WMS links where ai:group contains WMS_LINK_MARKER
220+
// Filter WFS links by ai:group marker, falling back to rel="wfs"
221221
return model.getLinks()
222222
.stream()
223-
.filter(link -> link.getAiGroup() != null)
224-
.filter(link -> link.getAiGroup().contains(WFS_LINK_MARKER))
223+
.filter(isWfsLink(WFS_LINK_MARKER))
225224
.toList();
226225
}
227226

@@ -482,13 +481,9 @@ protected Optional<List<String>> getAllFeatureServerUrls(String collectionId) {
482481
return Optional.of(
483482
model.getLinks()
484483
.stream()
485-
.filter(link -> link.getAiGroup() != null)
486-
.filter(link ->
487-
// This is the pattern for wfs link
488-
link.getAiGroup().contains(WFS_LINK_MARKER) ||
489-
// The data itself can be unclean, ows is another option where it works with wfs
490-
link.getHref().contains("/ows")
491-
)
484+
.filter(isWfsLink(WFS_LINK_MARKER)
485+
// The data itself can be unclean, ows is another option where it works with wfs
486+
.or(link -> link.getHref().contains("/ows")))
492487
.map(LinkModel::getHref)
493488
.toList()
494489
);
@@ -512,8 +507,7 @@ public Optional<String> getFeatureServerUrlByTitleOrQueryParam(String collection
512507
log.info("start to find wfs link for collectionId {} with layerName {}, total links to check {}", collectionId, layerName, model.getLinks().size());
513508
return model.getLinks()
514509
.stream()
515-
.filter(link -> link.getAiGroup() != null)
516-
.filter(link -> link.getAiGroup().contains(WFS_LINK_MARKER))
510+
.filter(isWfsLink(WFS_LINK_MARKER))
517511
.filter(link -> {
518512
Optional<String> name = extractLayernameOrTypenameFromUrl(link.getHref());
519513
return roughlyMatch(link.getTitle(), layerName) ||
@@ -611,11 +605,10 @@ public List<FeatureTypeInfo> filterFeatureTypesByWfsLinks(String collectionId, L
611605

612606
StacCollectionModel model = result.getCollections().get(0);
613607

614-
// Filter WFS links where ai:group contains "Data Access > wfs"
608+
// Filter WFS links by ai:group marker, falling back to rel="wfs"
615609
List<LinkModel> wfsLinks = model.getLinks()
616610
.stream()
617-
.filter(link -> link.getAiGroup() != null)
618-
.filter(link -> link.getAiGroup().contains(WFS_LINK_MARKER))
611+
.filter(isWfsLink(WFS_LINK_MARKER))
619612
.toList();
620613

621614
// Filter feature types based on matching with WFS links

server/src/main/java/au/org/aodn/ogcapi/server/core/service/geoserver/wms/WmsServer.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -449,11 +449,10 @@ protected Optional<String> getMapServerUrl(String collectionId, FeatureRequest r
449449
StacCollectionModel model = result.getCollections().get(0);
450450

451451
String layerName = request != null ? request.getLayerName() : null;
452-
// Filter for WMS links
452+
// Filter WMS links by ai:group marker, falling back to rel="wms"
453453
List<LinkModel> wmsLinks = model.getLinks()
454454
.stream()
455-
.filter(link -> link.getAiGroup() != null)
456-
.filter(link -> link.getAiGroup().contains(WMS_LINK_MARKER))
455+
.filter(isWmsLink(WMS_LINK_MARKER))
457456
.toList();
458457

459458
if (wmsLinks.isEmpty()) {
@@ -725,11 +724,10 @@ protected List<LinkModel> getWmsLinks(String collectionId) {
725724

726725
StacCollectionModel model = result.getCollections().get(0);
727726

728-
// Filter WMS links where ai:group contains WMS_LINK_MARKER
727+
// Filter WMS links by ai:group marker, falling back to rel="wms"
729728
return model.getLinks()
730729
.stream()
731-
.filter(link -> link.getAiGroup() != null)
732-
.filter(link -> link.getAiGroup().contains(WMS_LINK_MARKER))
730+
.filter(isWmsLink(WMS_LINK_MARKER))
733731
.toList();
734732
}
735733

server/src/main/java/au/org/aodn/ogcapi/server/core/util/GeoserverUtils.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,36 @@
88
import java.nio.charset.StandardCharsets;
99
import java.util.List;
1010
import java.util.Optional;
11+
import java.util.function.Predicate;
1112

1213
@Slf4j
1314
public class GeoserverUtils {
15+
/**
16+
* Predicate that matches a link as a WFS link.
17+
* Primary: link has ai:group containing the WFS marker.
18+
* Fallback: link has rel = "wfs" (for links without ai:group).
19+
*
20+
* @param wfsLinkMarker - The WFS marker string (e.g. "Data Access > wfs")
21+
* @return Predicate matching WFS links
22+
*/
23+
public static Predicate<LinkModel> isWfsLink(String wfsLinkMarker) {
24+
return link -> (link.getAiGroup() != null && link.getAiGroup().contains(wfsLinkMarker))
25+
|| "wfs".equalsIgnoreCase(link.getRel());
26+
}
27+
28+
/**
29+
* Predicate that matches a link as a WMS link.
30+
* Primary: link has ai:group containing the WMS marker.
31+
* Fallback: link has rel = "wms" (for links without ai:group).
32+
*
33+
* @param wmsLinkMarker - The WMS marker string (e.g. "Data Access > wms")
34+
* @return Predicate matching WMS links
35+
*/
36+
public static Predicate<LinkModel> isWmsLink(String wmsLinkMarker) {
37+
return link -> (link.getAiGroup() != null && link.getAiGroup().contains(wmsLinkMarker))
38+
|| "wms".equalsIgnoreCase(link.getRel());
39+
}
40+
1441
/**
1542
* Fuzzy match utility to compare layer names, ignoring namespace prefixes
1643
* For example: "underway:nuyina_underway_202122020" matches "nuyina_underway_202122020"

server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wfs/WfsServerTest.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
import java.util.Collections;
2727
import java.util.List;
28+
import java.util.Optional;
2829

2930
import static au.org.aodn.ogcapi.server.core.service.geoserver.wfs.WfsDefaultParam.WFS_LINK_MARKER;
3031
import static org.junit.jupiter.api.Assertions.*;
@@ -393,6 +394,28 @@ void createWfsRequestUrl_stripsOldParamsFromServerUrl() {
393394
assertEquals(1, requestCount, "REQUEST should appear exactly once");
394395
}
395396

397+
@Test
398+
void getFeatureServerUrl_withRelWfsFallback_returnsUrl() {
399+
// Link has rel="wfs" but no aiGroup — should be found via fallback
400+
String expectedUrl = "http://geoserver.example.com/geoserver/wfs";
401+
LinkModel wfsLink = LinkModel.builder()
402+
.rel("wfs")
403+
.href(expectedUrl)
404+
.title("test_layer")
405+
.build();
406+
407+
StacCollectionModel model = StacCollectionModel.builder().links(List.of(wfsLink)).build();
408+
ElasticSearchBase.SearchResult<StacCollectionModel> result = new ElasticSearchBase.SearchResult<>();
409+
result.setCollections(List.of(model));
410+
when(mockSearch.searchCollections(anyString())).thenReturn(result);
411+
412+
WfsServer server = new WfsServer(mockSearch, restTemplate, new RestTemplateUtils(restTemplate), entity, wfsDefaultParam);
413+
Optional<String> url = server.getFeatureServerUrl("id", "test_layer");
414+
415+
assertTrue(url.isPresent(), "URL should be found via rel=wfs fallback when aiGroup is absent");
416+
assertEquals(expectedUrl, url.get());
417+
}
418+
396419
@Test
397420
void createCapabilitiesQueryUrl_buildsCorrectUrl() {
398421
// arrange

server/src/test/java/au/org/aodn/ogcapi/server/core/service/geoserver/wms/WmsServerTest.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,48 @@ public void verifyHandleServiceExceptionReportCorrect() {
274274
"DownloadableFieldsNotFoundException expected when layer is not found on server");
275275
}
276276

277+
@Test
278+
public void describeLayer_withRelWmsFallback_returnsResult() {
279+
// Link has rel="wms" but no aiGroup — getMapServerUrl should find it via fallback
280+
FeatureRequest request = FeatureRequest.builder().layerName("imos:test_layer").build();
281+
282+
ElasticSearchBase.SearchResult<StacCollectionModel> stac = new ElasticSearchBase.SearchResult<>();
283+
stac.setCollections(new ArrayList<>());
284+
stac.getCollections().add(
285+
StacCollectionModel
286+
.builder()
287+
.links(List.of(
288+
LinkModel.builder()
289+
.rel("wms")
290+
.href("http://geoserver-123.aodn.org.au/geoserver/wms")
291+
.title(request.getLayerName())
292+
.build()) // no aiGroup
293+
)
294+
.build()
295+
);
296+
297+
String describeLayerXml = """
298+
<?xml version="1.0" encoding="UTF-8"?>
299+
<!DOCTYPE WMS_DescribeLayerResponse SYSTEM "https://geoserver-123.aodn.org.au/geoserver/schemas/wms/1.1.1/WMS_DescribeLayerResponse.dtd">
300+
<WMS_DescribeLayerResponse version="1.1.1">
301+
<LayerDescription name="imos:test_layer" wfs="https://geoserver-123.aodn.org.au/geoserver/wfs?" owsURL="https://geoserver-123.aodn.org.au/geoserver/wfs?" owsType="WFS">
302+
<Query typeName="imos:test_layer"/>
303+
</LayerDescription>
304+
</WMS_DescribeLayerResponse>""";
305+
306+
when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(entity), eq(String.class)))
307+
.thenReturn(ResponseEntity.ok(describeLayerXml));
308+
309+
String id = "id";
310+
when(search.searchCollections(eq(id))).thenReturn(stac);
311+
312+
DescribeLayerResponse response = wmsServer.describeLayer(id, request);
313+
314+
assertNotNull(response, "describeLayer should succeed when link is found via rel=wms fallback");
315+
assertNotNull(response.getLayerDescription());
316+
assertEquals("imos:test_layer", response.getLayerDescription().getName());
317+
}
318+
277319
@Test
278320
public void verifyParseCorrect() throws JsonProcessingException {
279321
DescribeLayerResponse value = wmsServer.xmlMapper.readValue(

0 commit comments

Comments
 (0)