From 94a6fb810edc474a1f6d0c6074af7433a6122f8b Mon Sep 17 00:00:00 2001 From: rng Date: Thu, 13 Nov 2025 09:46:29 +1100 Subject: [PATCH 1/4] Add cache url and fix issue on 403 due to server only allow browser based query --- .../core/configuration/WfsWmsConfig.java | 23 +++++++++++++--- .../ogcapi/server/core/service/CacheWarm.java | 10 +++++-- .../server/core/service/wfs/WfsServer.java | 14 ++++++++-- .../server/core/service/wms/WmsServer.java | 27 +++++++++---------- .../server/core/util/RestTemplateUtils.java | 7 ++--- .../server/core/configuration/TestConfig.java | 13 ++++++++- .../wfs/DownloadableFieldsServiceTest.java | 13 ++++++--- .../core/service/wms/WmsServerTest.java | 27 ++++++++++++++----- .../core/util/RestTemplateUtilsTest.java | 12 ++++----- .../server/service/wfs/WfsServerTest.java | 15 ++++++++--- 10 files changed, 114 insertions(+), 47 deletions(-) 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 9bbfdf87..d07ee883 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 @@ -5,23 +5,38 @@ 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.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; import org.springframework.web.client.RestTemplate; @Configuration public class WfsWmsConfig { + @ConditionalOnMissingBean(name="pretendUserEntity") + @Bean("pretendUserEntity") + public HttpEntity createPretendUserEntity() { + // Some server do not allow program to scrap the content, so we need to pretend to be a client + HttpHeaders headers = new HttpHeaders(); + headers.set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"); + + return new HttpEntity<>(headers); + } + @Bean public WfsServer createWfsServer(Search search, DownloadableFieldsService downloadableFieldsService, RestTemplate restTemplate, - RestTemplateUtils restTemplateUtils) { - return new WfsServer(search, downloadableFieldsService, restTemplate, restTemplateUtils); + RestTemplateUtils restTemplateUtils, + @Qualifier("pretendUserEntity") HttpEntity entity) { + return new WfsServer(search, downloadableFieldsService, restTemplate, restTemplateUtils, entity); } @Bean - public WmsServer createWmsServer() { - return new WmsServer(); + public WmsServer createWmsServer(@Qualifier("pretendUserEntity") HttpEntity entity) { + return new WmsServer(entity); } } 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 ac1a3226..03b3b687 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 @@ -7,6 +7,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheEvict; import org.springframework.context.annotation.Lazy; +import org.springframework.retry.annotation.Backoff; +import org.springframework.retry.annotation.Retryable; import org.springframework.scheduling.annotation.Scheduled; import java.util.List; import java.util.Map; @@ -17,7 +19,8 @@ */ @Slf4j public class CacheWarm { - // Hardcode server list as not expect to change much overtime, add more if needed + // Hardcode server list as not expect to change much overtime, add more if needed, the operation is + // heavy so we warm the cache when start protected List getCapabilitiesUrls = List.of( "https://data.aad.gov.au/geoserver/underway/wms", "https://www.cmar.csiro.au/geoserver/caab/wms", @@ -25,7 +28,9 @@ public class CacheWarm { "https://www.cmar.csiro.au/geoserver/ea-be/wms", "https://www.cmar.csiro.au/geoserver/gsfm/wms", "https://www.cmar.csiro.au/geoserver/nerp/wms", - "https://www.cmar.csiro.au/geoserver/AusSeabed/wms" + "https://www.cmar.csiro.au/geoserver/AusSeabed/wms", + "https://geoserver.apps.aims.gov.au/aims/wms", + "https://geoserver.apps.aims.gov.au/reefcloud/wms" ); protected WmsServer wmsServer; protected GeometryUtils geometryUtils; @@ -73,6 +78,7 @@ protected void evictGetCapabilities(String key){ ); } + @Retryable(maxAttempts = 3, backoff = @Backoff(delay = 1000)) protected void warmGetCapabilities(String url) { try { // Call and warm cache 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 69001000..25654bc2 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 @@ -16,6 +16,8 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import lombok.extern.slf4j.Slf4j; import org.springframework.cache.annotation.Cacheable; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; @@ -39,11 +41,13 @@ public class WfsServer { protected RestTemplateUtils restTemplateUtils; protected RestTemplate restTemplate; protected Search search; + protected HttpEntity pretendUserEntity; public WfsServer(Search search, DownloadableFieldsService downloadableFieldsService, RestTemplate restTemplate, - RestTemplateUtils restTemplateUtils) { + RestTemplateUtils restTemplateUtils, + HttpEntity entity) { xmlMapper = new XmlMapper(); xmlMapper.registerModule(new JavaTimeModule()); // Add JavaTimeModule @@ -53,6 +57,7 @@ public WfsServer(Search search, this.restTemplate = restTemplate; this.restTemplateUtils = restTemplateUtils; this.downloadableFieldsService = downloadableFieldsService; + this.pretendUserEntity = entity; } /** @@ -77,7 +82,12 @@ public List getDownloadableFields(String collectionId, F try { if (uri != null) { log.debug("Try Url to wfs {}", uri); - ResponseEntity response = restTemplateUtils.handleRedirect(uri, restTemplate.getForEntity(uri, String.class), String.class); + ResponseEntity response = restTemplateUtils.handleRedirect( + uri, + restTemplate.exchange(uri, HttpMethod.GET, pretendUserEntity, String.class), + String.class, + pretendUserEntity + ); if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) { return DownloadableFieldsService.convertWfsResponseToDownloadableFields( 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 c68a5e7e..6c8c66af 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 @@ -21,8 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; import org.springframework.context.annotation.Lazy; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponents; @@ -61,10 +60,14 @@ public class WmsServer { @Autowired protected WmsServer self; - public WmsServer() { + protected final HttpEntity pretendUserEntity; + + public WmsServer(HttpEntity entity) { xmlMapper = new XmlMapper(); xmlMapper.registerModule(new JavaTimeModule()); // Add JavaTimeModule xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + pretendUserEntity = entity; } /** * This function is used to append the CQL filter to the geonetwork query, it will guess the correct dataTime field by @@ -425,7 +428,7 @@ public FeatureInfoResponse getMapFeatures(String collectionId, FeatureRequest re List urls = createMapFeatureQueryUrl(mapServerUrl.get(), collectionId, request); // Try one by one, we exit when any works for (String url : urls) { - ResponseEntity response = restTemplateUtils.handleRedirect(url, restTemplate.getForEntity(url, String.class, Collections.emptyMap()), String.class); + ResponseEntity response = restTemplateUtils.handleRedirect(url, restTemplate.getForEntity(url, String.class, Collections.emptyMap()), String.class, pretendUserEntity); if (response.getStatusCode().is2xxSuccessful()) { // Now try to unify the return if (MediaType.TEXT_HTML.isCompatibleWith(response.getHeaders().getContentType())) { @@ -456,7 +459,7 @@ public DescribeLayerResponse describeLayer(String collectionId, FeatureRequest r // Try one by one, we exit when any works for (String url : urls) { try { - ResponseEntity response = restTemplateUtils.handleRedirect(url, restTemplate.getForEntity(url, String.class, Collections.emptyMap()), String.class); + ResponseEntity response = restTemplateUtils.handleRedirect(url, restTemplate.exchange(url, HttpMethod.GET, pretendUserEntity, String.class), String.class, pretendUserEntity); if (response.getStatusCode().is2xxSuccessful()) { DescribeLayerResponse layer = xmlMapper.readValue(response.getBody(), DescribeLayerResponse.class); if (layer.getLayerDescription() != null) { @@ -489,7 +492,7 @@ public byte[] getMapTile(String collectionId, FeatureRequest request) throws URI // Try one by one, we exit when any works for (String url : urls) { log.debug("map tile request for layer name {} url {} ", request.getLayerName(), url); - ResponseEntity response = restTemplateUtils.handleRedirect(url, restTemplate.getForEntity(url, byte[].class, Collections.emptyMap()), byte[].class); + ResponseEntity response = restTemplateUtils.handleRedirect(url, restTemplate.exchange(url, HttpMethod.GET, pretendUserEntity, byte[].class), byte[].class, pretendUserEntity); if (response.getStatusCode().is2xxSuccessful()) { return response.getBody(); } @@ -531,7 +534,7 @@ public List fetchCapabilitiesLayersByUrl(String wmsServerUrl) { // Build GetCapabilities URL UriComponentsBuilder builder = UriComponentsBuilder .newInstance() - .scheme(components.getScheme()) + .scheme("https") // hardcode to be https to avoid redirect .port(components.getPort()) .host(components.getHost()) .path(components.getPath() != null ? components.getPath() : "/geoserver/ows") @@ -541,12 +544,8 @@ public List fetchCapabilitiesLayersByUrl(String wmsServerUrl) { String url = builder.build().toUriString(); log.debug("GetCapabilities URL: {}", url); - // Make the HTTP call - ResponseEntity response = restTemplateUtils.handleRedirect( - url, - restTemplate.getForEntity(url, String.class, Collections.emptyMap()), - String.class - ); + // Make the HTTPS call + ResponseEntity response = restTemplate.exchange(url, HttpMethod.GET, pretendUserEntity, String.class); if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) { // Parse XML response @@ -569,7 +568,7 @@ public List fetchCapabilitiesLayersByUrl(String wmsServerUrl) { return layers; } } - } catch (RestClientException | URISyntaxException | JsonProcessingException e) { + } catch (RestClientException | JsonProcessingException e) { log.error("Error fetching GetCapabilities for URL: {}", wmsServerUrl, e); throw new RuntimeException(e); } diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/util/RestTemplateUtils.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/util/RestTemplateUtils.java index daddd830..1ed8b5b1 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/util/RestTemplateUtils.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/util/RestTemplateUtils.java @@ -1,11 +1,12 @@ package au.org.aodn.ogcapi.server.core.util; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; import java.net.URISyntaxException; -import java.util.Collections; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -27,7 +28,7 @@ public RestTemplateUtils(RestTemplate restTemplate) { * @param The type of the return type * @throws URISyntaxException - Not expect to throw */ - public ResponseEntity handleRedirect(String sourceUrl, ResponseEntity response, Class type) throws URISyntaxException { + public ResponseEntity handleRedirect(String sourceUrl, ResponseEntity response, Class type, HttpEntity entity) throws URISyntaxException { // Redirect should happen automatically but it does not so here is a safe-guard // the reason happens because http is use but redirect to https if(response != null && response.getStatusCode().is3xxRedirection() && response.getHeaders().getLocation() != null) { @@ -44,7 +45,7 @@ public ResponseEntity handleRedirect(String sourceUrl, ResponseEntity if(haveSameHost(sourceUrl, redirect)) { // Only allow redirect to same server. log.info("Redirect from {} to {}", sourceUrl , redirect); - return restTemplate.getForEntity(redirect, type, Collections.emptyMap()); + return restTemplate.exchange(redirect, HttpMethod.GET, entity, type); } else { log.error("Redirect to different host not allowed, from {} to {}", sourceUrl , redirect); diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/configuration/TestConfig.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/configuration/TestConfig.java index 040cbf22..dd41d625 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/configuration/TestConfig.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/configuration/TestConfig.java @@ -1,10 +1,11 @@ package au.org.aodn.ogcapi.server.core.configuration; -import au.org.aodn.ogcapi.server.core.service.Search; import org.mockito.Mockito; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; import org.springframework.web.client.RestTemplate; @Configuration @@ -15,4 +16,14 @@ public class TestConfig { public RestTemplate createMockRestTemplate() { return Mockito.mock(RestTemplate.class); } + + @Bean("pretendUserEntity") + @Primary + public HttpEntity createPretendUserEntity() { + // Satisfy depends + HttpHeaders headers = new HttpHeaders(); + headers.set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"); + + return new HttpEntity<>(headers); + } } diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadableFieldsServiceTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadableFieldsServiceTest.java index a973be78..38eca7a9 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadableFieldsServiceTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadableFieldsServiceTest.java @@ -19,9 +19,12 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.context.bean.override.mockito.MockitoBean; @@ -64,6 +67,10 @@ public class DownloadableFieldsServiceTest { @Autowired private WfsServer wfsServer; + @Autowired + @Qualifier("pretendUserEntity") + private HttpEntity entity; + @MockitoBean private DasService dasService; @@ -133,7 +140,7 @@ public void testGetDownloadableFieldsSuccess() { String id = "id"; - when(restTemplate.getForEntity(any(String.class), eq(String.class))) + when(restTemplate.exchange(any(String.class), eq(HttpMethod.GET), eq(entity), eq(String.class))) .thenReturn(new ResponseEntity<>(mockWfsResponse, HttpStatus.OK)); when(search.searchCollections(eq(id))) @@ -203,7 +210,7 @@ public void testGetDownloadableFieldsEmptyResponse() { String id = "id2"; - when(restTemplate.getForEntity(any(String.class), eq(String.class))) + when(restTemplate.exchange(any(String.class), eq(HttpMethod.GET), eq(entity), eq(String.class))) .thenReturn(new ResponseEntity<>(mockWfsResponse, HttpStatus.NOT_FOUND)); when(search.searchCollections(eq(id))) @@ -244,7 +251,7 @@ public void testGetDownloadableFieldsWfsError() { when(search.searchCollections(eq(id))) .thenReturn(stac); - when(restTemplate.getForEntity(any(String.class), eq(String.class))) + when(restTemplate.exchange(any(String.class), eq(HttpMethod.GET), eq(entity), eq(String.class))) .thenReturn(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); DownloadableFieldsNotFoundException exception = assertThrows( diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServerTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServerTest.java index cf4ec53d..387cd458 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServerTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wms/WmsServerTest.java @@ -15,9 +15,12 @@ import org.junit.jupiter.api.*; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.web.client.RestTemplate; @@ -26,9 +29,7 @@ import java.math.BigDecimal; import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import java.util.Optional; import static au.org.aodn.ogcapi.server.core.service.wfs.WfsDefaultParam.WFS_LINK_MARKER; import static au.org.aodn.ogcapi.server.core.service.wms.WmsDefaultParam.WMS_LINK_MARKER; @@ -60,6 +61,10 @@ public class WmsServerTest { @Autowired protected WmsServer wmsServer; + @Autowired + @Qualifier("pretendUserEntity") + private HttpEntity entity; + @BeforeEach public void before() { Mockito.reset(restTemplate); @@ -255,7 +260,7 @@ public void verifyHandleServiceExceptionReportCorrect() { "\n" + ""; - when(restTemplate.getForEntity(anyString(), eq(String.class), eq(Collections.emptyMap()))) + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(entity), eq(String.class))) .thenReturn(ResponseEntity.ok(r)); String id = "id"; @@ -332,8 +337,10 @@ public void verifyCreateCQLSingleDateTime() throws JsonProcessingException { when(search.searchCollections(eq(uuid))) .thenReturn(stac); - when(restTemplate.getForEntity( + when(restTemplate.exchange( anyString(), + eq(HttpMethod.GET), + eq(entity), eq(String.class)) ).thenReturn(ResponseEntity.ok(value)); @@ -391,8 +398,10 @@ public void verifyCreateCQLSingleDateTimeWithCQL() throws JsonProcessingExceptio when(search.searchCollections(eq(uuid))) .thenReturn(stac); - when(restTemplate.getForEntity( + when(restTemplate.exchange( anyString(), + eq(HttpMethod.GET), + eq(entity), eq(String.class)) ).thenReturn(ResponseEntity.ok(value)); @@ -483,8 +492,10 @@ public void verifyCreateCQLMultiDateTimeWithCQL() throws JsonProcessingException when(search.searchCollections(eq(uuid))) .thenReturn(stac); - when(restTemplate.getForEntity( + when(restTemplate.exchange( anyString(), + eq(HttpMethod.GET), + eq(entity), eq(String.class)) ).thenReturn(ResponseEntity.ok(value)); @@ -575,8 +586,10 @@ public void verifyCreateCQLRangeDateTimeWithCQL() throws JsonProcessingException when(search.searchCollections(eq(uuid))) .thenReturn(stac); - when(restTemplate.getForEntity( + when(restTemplate.exchange( anyString(), + eq(HttpMethod.GET), + eq(entity), eq(String.class)) ).thenReturn(ResponseEntity.ok(value)); diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/util/RestTemplateUtilsTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/util/RestTemplateUtilsTest.java index bf32e72b..731360d7 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/util/RestTemplateUtilsTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/util/RestTemplateUtilsTest.java @@ -6,9 +6,7 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; import org.springframework.web.client.RestTemplate; import java.net.URI; @@ -43,11 +41,11 @@ public void testHandleRedirectSameHostRedirectFollowed() throws URISyntaxExcepti ResponseEntity response = new ResponseEntity<>(null, headers, HttpStatus.MOVED_PERMANENTLY); ResponseEntity redirectResponse = new ResponseEntity<>("Redirected content", HttpStatus.OK); - when(restTemplate.getForEntity(eq(redirectUrl.replace("%20", " ")), eq(String.class), eq(Collections.emptyMap()))) + when(restTemplate.exchange(eq(redirectUrl.replace("%20", " ")), eq(HttpMethod.GET), any(), eq(String.class))) .thenReturn(redirectResponse); // Act - ResponseEntity result = restTemplateUtils.handleRedirect(sourceUrl, response, String.class); + ResponseEntity result = restTemplateUtils.handleRedirect(sourceUrl, response, String.class, new HttpEntity<>(null)); // Assert assertEquals(HttpStatus.OK, result.getStatusCode()); @@ -65,7 +63,7 @@ public void testHandleRedirectDifferentHostRedirectNotFollowed() throws URISynta ResponseEntity response = new ResponseEntity<>(null, headers, HttpStatus.FOUND); // Act - ResponseEntity result = restTemplateUtils.handleRedirect(sourceUrl, response, String.class); + ResponseEntity result = restTemplateUtils.handleRedirect(sourceUrl, response, String.class, new HttpEntity<>(null)); // Assert assertEquals(response, result); @@ -84,7 +82,7 @@ public void verifyCQLFilterPreserved() throws URISyntaxException { ResponseEntity response = new ResponseEntity<>(null, headers, HttpStatus.MOVED_PERMANENTLY); // Act - restTemplateUtils.handleRedirect(sourceUrl, response, String.class); + restTemplateUtils.handleRedirect(sourceUrl, response, String.class, new HttpEntity<>(null)); // Assert verify(restTemplate, times(1)) 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 92f113d0..ca18872d 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 @@ -13,6 +13,9 @@ import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.HttpEntity; import org.springframework.web.client.RestTemplate; import java.util.Collections; @@ -35,6 +38,10 @@ public class WfsServerTest { @Mock RestTemplate restTemplate; + @Autowired + @Qualifier("pretendUserEntity") + private HttpEntity entity; + AutoCloseable closeableMock; @BeforeEach @@ -55,7 +62,7 @@ void noCollection_returnsEmptyLayers() { result.setCollections(Collections.emptyList()); when(mockSearch.searchCollections(anyString())).thenReturn(result); - WfsServer server = new WfsServer(mockSearch, downloadableFieldsService, restTemplate, new RestTemplateUtils(restTemplate)); + WfsServer server = new WfsServer(mockSearch, downloadableFieldsService, restTemplate, new RestTemplateUtils(restTemplate), entity); List layers = Collections.singletonList(LayerInfo.builder().build()); assertEquals(Collections.emptyList(), server.filterLayersByWfsLinks("id", layers)); @@ -71,7 +78,7 @@ void noWfsLinks_returnsEmptyLayers() { when(mockSearch.searchCollections(anyString())).thenReturn(result); - WfsServer server = new WfsServer(mockSearch, downloadableFieldsService, restTemplate, new RestTemplateUtils(restTemplate)); + WfsServer server = new WfsServer(mockSearch, downloadableFieldsService, restTemplate, new RestTemplateUtils(restTemplate), entity); List layers = Collections.singletonList(LayerInfo.builder().build()); assertEquals(Collections.emptyList(), server.filterLayersByWfsLinks("id", layers)); @@ -96,7 +103,7 @@ void primaryTitleMatch_filtersMatchingLayers() { result.setCollections(List.of(model)); when(mockSearch.searchCollections(anyString())).thenReturn(result); - WfsServer server = new WfsServer(mockSearch, downloadableFieldsService, restTemplate, new RestTemplateUtils(restTemplate)); + WfsServer server = new WfsServer(mockSearch, downloadableFieldsService, restTemplate, new RestTemplateUtils(restTemplate), entity); List info = server.filterLayersByWfsLinks("id", layers); assertEquals(1, info.size(), "Layer count match"); @@ -124,7 +131,7 @@ void primaryTitleMatch_filtersPreferAodnMapLayers() { result.setCollections(List.of(model)); when(mockSearch.searchCollections(anyString())).thenReturn(result); - WfsServer server = new WfsServer(mockSearch, downloadableFieldsService, restTemplate, new RestTemplateUtils(restTemplate)); + WfsServer server = new WfsServer(mockSearch, downloadableFieldsService, restTemplate, new RestTemplateUtils(restTemplate), entity); List info = server.filterLayersByWfsLinks("id", layers); assertEquals(1, info.size(), "Layer count match"); From b541e2be56f42c6c70ce0780f9f60d6f871de3d0 Mon Sep 17 00:00:00 2001 From: rng Date: Thu, 13 Nov 2025 09:54:31 +1100 Subject: [PATCH 2/4] Miss to change two functions --- .../server/core/service/wfs/DownloadableFieldsServiceTest.java | 2 +- .../aodn/ogcapi/server/core/util/RestTemplateUtilsTest.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadableFieldsServiceTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadableFieldsServiceTest.java index 38eca7a9..3cfccdb5 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadableFieldsServiceTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/service/wfs/DownloadableFieldsServiceTest.java @@ -287,7 +287,7 @@ public void testGetDownloadableFieldsNetworkError() { .thenReturn(stac); // Mock network error - when(restTemplate.getForEntity(any(String.class), eq(String.class))) + when(restTemplate.exchange(any(String.class), eq(HttpMethod.GET), eq(entity), eq(String.class))) .thenThrow(new RuntimeException("Connection timeout")); RuntimeException exception = assertThrows( diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/util/RestTemplateUtilsTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/util/RestTemplateUtilsTest.java index 731360d7..1d34a7fe 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/util/RestTemplateUtilsTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/util/RestTemplateUtilsTest.java @@ -11,7 +11,6 @@ import java.net.URI; import java.net.URISyntaxException; -import java.util.Collections; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; @@ -50,7 +49,7 @@ public void testHandleRedirectSameHostRedirectFollowed() throws URISyntaxExcepti // Assert assertEquals(HttpStatus.OK, result.getStatusCode()); assertEquals("Redirected content", result.getBody()); - verify(restTemplate, times(1)).getForEntity(eq(redirectUrl.replace("%20", " ")), eq(String.class), eq(Collections.emptyMap())); + verify(restTemplate, times(1)).exchange(eq(redirectUrl.replace("%20", " ")), eq(HttpMethod.GET), any(), eq(String.class)); } @Test From 953b446a657f2e719a50f5dd0e85a57eb9cbc2c1 Mon Sep 17 00:00:00 2001 From: rng Date: Thu, 13 Nov 2025 10:07:46 +1100 Subject: [PATCH 3/4] Miss to change two functions --- .../org/aodn/ogcapi/server/core/util/RestTemplateUtilsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/util/RestTemplateUtilsTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/util/RestTemplateUtilsTest.java index 1d34a7fe..21957f57 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/util/RestTemplateUtilsTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/util/RestTemplateUtilsTest.java @@ -85,6 +85,6 @@ public void verifyCQLFilterPreserved() throws URISyntaxException { // Assert verify(restTemplate, times(1)) - .getForEntity(eq(redirectUrl.replace("%20", " ")), eq(String.class), anyMap()); + .exchange(eq(redirectUrl.replace("%20", " ")), eq(HttpMethod.GET), any(), eq(String.class), anyMap()); } } From 7c846a505cb81d1d19f1fe5a508ef3bfa6874b9c Mon Sep 17 00:00:00 2001 From: rng Date: Thu, 13 Nov 2025 10:08:02 +1100 Subject: [PATCH 4/4] Miss to change two functions --- .../org/aodn/ogcapi/server/core/util/RestTemplateUtilsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/core/util/RestTemplateUtilsTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/core/util/RestTemplateUtilsTest.java index 21957f57..fd1811c1 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/core/util/RestTemplateUtilsTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/core/util/RestTemplateUtilsTest.java @@ -85,6 +85,6 @@ public void verifyCQLFilterPreserved() throws URISyntaxException { // Assert verify(restTemplate, times(1)) - .exchange(eq(redirectUrl.replace("%20", " ")), eq(HttpMethod.GET), any(), eq(String.class), anyMap()); + .exchange(eq(redirectUrl.replace("%20", " ")), eq(HttpMethod.GET), any(), eq(String.class)); } }