diff --git a/src/apps/geoserver/gwc/src/test/java/org/geoserver/cloud/gwc/app/GeoWebCacheApplicationTest.java b/src/apps/geoserver/gwc/src/test/java/org/geoserver/cloud/gwc/app/GeoWebCacheApplicationTest.java index 7fcffb432..73e86cb15 100644 --- a/src/apps/geoserver/gwc/src/test/java/org/geoserver/cloud/gwc/app/GeoWebCacheApplicationTest.java +++ b/src/apps/geoserver/gwc/src/test/java/org/geoserver/cloud/gwc/app/GeoWebCacheApplicationTest.java @@ -10,6 +10,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonParser; +import java.net.URI; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -57,4 +58,31 @@ protected ResponseEntity testGetRequestContentType(String uri, MediaType assertThat(response.getHeaders().getContentType()).isEqualTo(expected); return response; } + + @Test + void testPostSeedDoesNotThrowAmbiguousHandlerMapping() { + String payload = + """ + + workspace:layer + 3857 + 0 + 8 + image/png + reseed + 2 + + """; + String uri = "/gwc/rest/seed/workspace:layer.xml"; + + ResponseEntity response = restTemplate.postForEntity(URI.create(uri), payload, String.class); + HttpStatus statusCode = response.getStatusCode(); + String body = response.getBody(); + + // SeedService will throw a 500 error when the layer is not found + // it's ok we just need to check it doesn't result in an "ambiguous handler mapping" error + // see org.geoserver.cloud.gwc.config.services.SeedController + assertThat(statusCode).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR); + assertThat(body).contains("Unknown layer workspace:layer"); + } } diff --git a/src/gwc/services/src/main/java/org/geoserver/cloud/gwc/config/services/RESTConfigConfiguration.java b/src/gwc/services/src/main/java/org/geoserver/cloud/gwc/config/services/RESTConfigConfiguration.java index 485ebd3b0..adc9b4372 100644 --- a/src/gwc/services/src/main/java/org/geoserver/cloud/gwc/config/services/RESTConfigConfiguration.java +++ b/src/gwc/services/src/main/java/org/geoserver/cloud/gwc/config/services/RESTConfigConfiguration.java @@ -7,12 +7,14 @@ import org.geoserver.catalog.Catalog; import org.geoserver.gwc.controller.GwcUrlHandlerMapping; import org.geoserver.gwc.layer.GWCGeoServerRESTConfigurationProvider; +import org.geowebcache.rest.controller.SeedController; import org.geowebcache.rest.converter.GWCConverter; import org.geowebcache.util.ApplicationContextProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; /** * The original {@literal geowebcache-rest-context.xml}: @@ -51,9 +53,16 @@ */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(GWCConverter.class) -@ComponentScan(basePackages = "org.geowebcache.rest") +@ComponentScan( + basePackages = "org.geowebcache.rest", + excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SeedController.class)) public class RESTConfigConfiguration { + @Bean + org.geoserver.cloud.gwc.config.services.SeedController seedController() { + return new org.geoserver.cloud.gwc.config.services.SeedController(); + } + /** * The original {@literal geowebcache-rest-context.xml}: * diff --git a/src/gwc/services/src/main/java/org/geoserver/cloud/gwc/config/services/SeedController.java b/src/gwc/services/src/main/java/org/geoserver/cloud/gwc/config/services/SeedController.java new file mode 100644 index 000000000..4a08217ec --- /dev/null +++ b/src/gwc/services/src/main/java/org/geoserver/cloud/gwc/config/services/SeedController.java @@ -0,0 +1,46 @@ +/* + * (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.cloud.gwc.config.services; + +import java.io.InputStream; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.*; + +@Component +@RestController +@RequestMapping(path = "${gwc.context.suffix:}/rest") +public class SeedController extends org.geowebcache.rest.controller.SeedController { + + /** + * + * {@inheritDoc} + *

+ * Override for the {@code path} pattern to exclude {@code .xml} and + * {@code .json} suffixes to avoid an exception like the following with + * {@link #seedOrTruncateWithJsonPayload} and + * {@link #seedOrTruncateWithXmlPayload}: + *

+     * 
+     * java.lang.IllegalStateException: Ambiguous handler methods mapped for '.../rest/seed/workspace:layer.xml': {
+     *   public org.springframework.http.ResponseEntity org.geoserver.cloud.gwc.config.services.SeedController.seedOrTruncateWithXmlPayload(...),
+     *   public org.springframework.http.ResponseEntity org.geoserver.cloud.gwc.config.services.SeedController.doPost(...)
+     *  }
+     * 
+     * 
+ */ + @Override + @PostMapping("/seed/{layer:^(?!.*\\.(?:xml|json)$).+}") + public ResponseEntity doPost( + HttpServletRequest request, + InputStream inputStream, + @PathVariable String layer, + @RequestParam Map params) { + + return super.doPost(request, inputStream, layer, params); + } +}