Support multiple paths in DispatcherServletPathProvider

Closes gh-13603
This commit is contained in:
Madhura Bhave
2018-06-28 11:57:19 -07:00
parent 43ea78f2ce
commit fddc9e9c7e
11 changed files with 198 additions and 74 deletions

View File

@@ -17,6 +17,8 @@
package org.springframework.boot.actuate.endpoint.web;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
@@ -27,26 +29,38 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
/**
* {@link ServletContextInitializer} to register {@link ExposableServletEndpoint servlet
* endpoints}.
*
* @author Phillip Webb
* @author Madhura Bhave
* @since 2.0.0
*/
public class ServletEndpointRegistrar implements ServletContextInitializer {
private static final Log logger = LogFactory.getLog(ServletEndpointRegistrar.class);
private final String basePath;
private final Set<String> basePaths = new LinkedHashSet<>();
private final Collection<ExposableServletEndpoint> servletEndpoints;
public ServletEndpointRegistrar(String basePath,
Collection<ExposableServletEndpoint> servletEndpoints) {
Assert.notNull(servletEndpoints, "ServletEndpoints must not be null");
this.basePath = (basePath != null ? basePath : "");
this.basePaths.add((basePath != null ? basePath : ""));
this.servletEndpoints = servletEndpoints;
}
public ServletEndpointRegistrar(Set<String> basePaths,
Collection<ExposableServletEndpoint> servletEndpoints) {
Assert.notNull(servletEndpoints, "ServletEndpoints must not be null");
this.basePaths.addAll(basePaths);
if (CollectionUtils.isEmpty(this.basePaths)) {
this.basePaths.add("");
}
this.servletEndpoints = servletEndpoints;
}
@@ -59,14 +73,20 @@ public class ServletEndpointRegistrar implements ServletContextInitializer {
private void register(ServletContext servletContext,
ExposableServletEndpoint endpoint) {
String name = endpoint.getId() + "-actuator-endpoint";
String path = this.basePath + "/" + endpoint.getRootPath();
String urlMapping = (path.endsWith("/") ? path + "*" : path + "/*");
EndpointServlet endpointServlet = endpoint.getEndpointServlet();
Dynamic registration = servletContext.addServlet(name,
endpointServlet.getServlet());
registration.addMapping(urlMapping);
registration.addMapping(getUrlMappings(endpoint.getRootPath(), name));
registration.setInitParameters(endpointServlet.getInitParameters());
logger.info("Registered '" + path + "' to " + name);
}
private String[] getUrlMappings(String endpointPath, String name) {
return this.basePaths.stream()
.map((bp) -> (bp != null ? bp + "/" + endpointPath : "/" + endpointPath))
.distinct().map((p) -> {
logger.info("Registered '" + p + "' to " + name);
return (p.endsWith("/") ? p + "*" : p + "/*");
}).toArray(String[]::new);
}
}

View File

@@ -18,6 +18,8 @@ package org.springframework.boot.actuate.endpoint.web;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.servlet.GenericServlet;
import javax.servlet.Servlet;
@@ -47,6 +49,7 @@ import static org.mockito.Mockito.verify;
* Tests for {@link ServletEndpointRegistrar}.
*
* @author Phillip Webb
* @author Madhura Bhave
*/
public class ServletEndpointRegistrarTests {
@@ -73,14 +76,14 @@ public class ServletEndpointRegistrarTests {
public void createWhenServletEndpointsIsNullShouldThrowException() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("ServletEndpoints must not be null");
new ServletEndpointRegistrar(null, null);
new ServletEndpointRegistrar((String) null, null);
}
@Test
public void onStartupShouldRegisterServlets() throws Exception {
ExposableServletEndpoint endpoint = mockEndpoint(
new EndpointServlet(TestServlet.class));
ServletEndpointRegistrar registrar = new ServletEndpointRegistrar(null,
ServletEndpointRegistrar registrar = new ServletEndpointRegistrar((String) null,
Collections.singleton(endpoint));
registrar.onStartup(this.servletContext);
verify(this.servletContext).addServlet(eq("test-actuator-endpoint"),
@@ -102,6 +105,64 @@ public class ServletEndpointRegistrarTests {
verify(this.dynamic).addMapping("/actuator/test/*");
}
@Test
public void onStartupWhenHasMultipleBasePathsShouldIncludeAllBasePaths()
throws Exception {
ExposableServletEndpoint endpoint = mockEndpoint(
new EndpointServlet(TestServlet.class));
Set<String> basePaths = new LinkedHashSet<>();
basePaths.add("/actuator");
basePaths.add("/admin");
basePaths.add("/application");
ServletEndpointRegistrar registrar = new ServletEndpointRegistrar(basePaths,
Collections.singleton(endpoint));
registrar.onStartup(this.servletContext);
verify(this.servletContext).addServlet(eq("test-actuator-endpoint"),
this.servlet.capture());
assertThat(this.servlet.getValue()).isInstanceOf(TestServlet.class);
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(this.dynamic).addMapping(captor.capture());
assertThat(captor.getAllValues()).containsExactlyInAnyOrder("/application/test/*",
"/admin/test/*", "/actuator/test/*");
}
@Test
public void onStartupWhenHasEmptyBasePathsShouldIncludeRoot() throws Exception {
ExposableServletEndpoint endpoint = mockEndpoint(
new EndpointServlet(TestServlet.class));
Set<String> basePaths = Collections.emptySet();
ServletEndpointRegistrar registrar = new ServletEndpointRegistrar(basePaths,
Collections.singleton(endpoint));
registrar.onStartup(this.servletContext);
verify(this.dynamic).addMapping("/test/*");
}
@Test
public void onStartupWhenHasBasePathsHasNullValueShouldIncludeRoot()
throws Exception {
ExposableServletEndpoint endpoint = mockEndpoint(
new EndpointServlet(TestServlet.class));
Set<String> basePaths = new LinkedHashSet<>();
basePaths.add(null);
ServletEndpointRegistrar registrar = new ServletEndpointRegistrar(basePaths,
Collections.singleton(endpoint));
registrar.onStartup(this.servletContext);
verify(this.dynamic).addMapping("/test/*");
}
@Test
public void onStartupWhenDuplicateValuesShouldIncludeDistinct() throws Exception {
ExposableServletEndpoint endpoint = mockEndpoint(
new EndpointServlet(TestServlet.class));
Set<String> basePaths = new LinkedHashSet<>();
basePaths.add("");
basePaths.add(null);
ServletEndpointRegistrar registrar = new ServletEndpointRegistrar(basePaths,
Collections.singleton(endpoint));
registrar.onStartup(this.servletContext);
verify(this.dynamic).addMapping("/test/*");
}
@Test
public void onStartupWhenHasInitParametersShouldRegisterInitParameters()
throws Exception {