Rework mappings endpoint
Improve the structure of the response and include mappings from WebFlux and Servlet and Filter registrations in addition to the mappings from Spring MVC. Closes gh-9979
This commit is contained in:
@@ -435,6 +435,11 @@
|
||||
<artifactId>spring-restdocs-mockmvc</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.restdocs</groupId>
|
||||
<artifactId>spring-restdocs-webtestclient</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-test</artifactId>
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
[[mappings]]
|
||||
= Mappings (`mappings`)
|
||||
|
||||
The `mappings` endpoint provides information about the application's request mappings.
|
||||
|
||||
|
||||
|
||||
[[mappings-retrieving]]
|
||||
== Retrieving the Mappings
|
||||
|
||||
To retrieve the mappings, make a `GET` request to `/actuator/mappings`, as shown in the
|
||||
following curl-based example:
|
||||
|
||||
include::{snippets}mappings/curl-request.adoc[]
|
||||
|
||||
The resulting response is similar to the following:
|
||||
|
||||
include::{snippets}mappings/http-response.adoc[]
|
||||
|
||||
|
||||
|
||||
[[mappings-retrieving-response-structure]]
|
||||
=== Response Structure
|
||||
|
||||
The response contains details of the application's mappings. The items found in the
|
||||
response depend on the type of web application (reactive or Servlet-based). The
|
||||
following table describes the structure of the common elements of the response:
|
||||
|
||||
[cols="2,1,3"]
|
||||
include::{snippets}mappings/response-fields.adoc[]
|
||||
|
||||
The entries that may be found in `contexts.*.mappings` are described in the
|
||||
following sections.
|
||||
|
||||
|
||||
[[mappings-retrieving-response-structure-dispatcher-servlets]]
|
||||
=== Dispatcher Servlets Response Structure
|
||||
|
||||
When using Spring MVC, the response contains details of any `DispatcherServlet`
|
||||
request mappings beneath `contexts.*.mappings.dispatcherServlets`. The following
|
||||
table describes the structure of this section of the response:
|
||||
|
||||
[cols="2,1,3"]
|
||||
include::{snippets}mappings/response-fields-dispatcher-servlets.adoc[]
|
||||
|
||||
|
||||
|
||||
[[mappings-retrieving-response-structure-servlets]]
|
||||
=== Servlets Response Structure
|
||||
|
||||
When using the Servlet stack, the response contains details of any `Servlet` mappings
|
||||
beneath `contexts.*.mappings.servlets`. The following table describes the structure of
|
||||
this section of the response:
|
||||
|
||||
[cols="2,1,3"]
|
||||
include::{snippets}mappings/response-fields-servlets.adoc[]
|
||||
|
||||
|
||||
|
||||
[[mappings-retrieving-response-structure-servlet-filters]]
|
||||
=== Servlet Filters Response Structure
|
||||
|
||||
When using the Servlet stack, the response contains details of any `Filter` mappings
|
||||
beneath `contexts.*.mappings.servletFilters`. The following table describes the
|
||||
structure of this section of the response:
|
||||
|
||||
[cols="2,1,3"]
|
||||
include::{snippets}mappings/response-fields-servlet-filters.adoc[]
|
||||
|
||||
|
||||
|
||||
[[mappings-retrieving-response-structure-dispatcher-servlets]]
|
||||
=== Dispatcher Handlers Response Structure
|
||||
|
||||
When using Spring WebFlux, the response contains details of any `DispatcherHandler`
|
||||
request mappings beneath `contexts.*.mappings.dispatcherHandlers`. The following
|
||||
table describes the structure of this section of the response:
|
||||
|
||||
[cols="2,1,3"]
|
||||
include::{snippets}mappings/response-fields-dispatcher-handlers.adoc[]
|
||||
@@ -61,6 +61,7 @@ include::endpoints/info.adoc[leveloffset=+1]
|
||||
include::endpoints/liquibase.adoc[leveloffset=+1]
|
||||
include::endpoints/logfile.adoc[leveloffset=+1]
|
||||
include::endpoints/loggers.adoc[leveloffset=+1]
|
||||
include::endpoints/mappings.adoc[leveloffset=+1]
|
||||
include::endpoints/metrics.adoc[leveloffset=+1]
|
||||
include::endpoints/prometheus.adoc[leveloffset=+1]
|
||||
include::endpoints/scheduledtasks.adoc[leveloffset=+1]
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.web;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
|
||||
import org.springframework.boot.actuate.web.MappingDescriptionProvider;
|
||||
import org.springframework.boot.actuate.web.MappingsEndpoint;
|
||||
import org.springframework.boot.actuate.web.reactive.DispatcherHandlersMappingDescriptionProvider;
|
||||
import org.springframework.boot.actuate.web.servlet.DispatcherServletsMappingDescriptionProvider;
|
||||
import org.springframework.boot.actuate.web.servlet.FiltersMappingDescriptionProvider;
|
||||
import org.springframework.boot.actuate.web.servlet.ServletsMappingDescriptionProvider;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.reactive.DispatcherHandler;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link MappingsEndpoint}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@ManagementContextConfiguration
|
||||
public class MappingsEndpointAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnEnabledEndpoint
|
||||
public MappingsEndpoint mappingsEndpoint(ApplicationContext applicationContext,
|
||||
ObjectProvider<Collection<MappingDescriptionProvider>> descriptionProviders) {
|
||||
return new MappingsEndpoint(
|
||||
descriptionProviders.getIfAvailable(Collections::emptyList),
|
||||
applicationContext);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||
static class ServletWebConfiguration {
|
||||
|
||||
@Bean
|
||||
ServletsMappingDescriptionProvider servletMappingDescriptionProvider() {
|
||||
return new ServletsMappingDescriptionProvider();
|
||||
}
|
||||
|
||||
@Bean
|
||||
FiltersMappingDescriptionProvider filterMappingDescriptionProvider() {
|
||||
return new FiltersMappingDescriptionProvider();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(DispatcherServlet.class)
|
||||
@ConditionalOnBean(DispatcherServlet.class)
|
||||
static class SpringMvcConfiguration {
|
||||
|
||||
@Bean
|
||||
DispatcherServletsMappingDescriptionProvider dispatcherServletMappingDescriptionProvider(
|
||||
ApplicationContext applicationContext) {
|
||||
return new DispatcherServletsMappingDescriptionProvider();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnWebApplication(type = Type.REACTIVE)
|
||||
@ConditionalOnClass(DispatcherHandler.class)
|
||||
@ConditionalOnBean(DispatcherHandler.class)
|
||||
static class ReactiveWebConfiguration {
|
||||
|
||||
@Bean
|
||||
public DispatcherHandlersMappingDescriptionProvider dispatcherHandlerMappingDescriptionProvider(
|
||||
ApplicationContext applicationContext) {
|
||||
return new DispatcherHandlersMappingDescriptionProvider();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.web.servlet;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
|
||||
import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;
|
||||
|
||||
/**
|
||||
* {@link Endpoint} to expose Spring MVC mappings.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Endpoint(id = "mappings")
|
||||
public class RequestMappingEndpoint implements ApplicationContextAware {
|
||||
|
||||
private List<AbstractUrlHandlerMapping> handlerMappings = Collections.emptyList();
|
||||
|
||||
private List<AbstractHandlerMethodMapping<?>> methodMappings = Collections
|
||||
.emptyList();
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the handler mappings.
|
||||
* @param handlerMappings the handler mappings
|
||||
*/
|
||||
public void setHandlerMappings(List<AbstractUrlHandlerMapping> handlerMappings) {
|
||||
this.handlerMappings = handlerMappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the method mappings.
|
||||
* @param methodMappings the method mappings
|
||||
*/
|
||||
public void setMethodMappings(List<AbstractHandlerMethodMapping<?>> methodMappings) {
|
||||
this.methodMappings = methodMappings;
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public Map<String, Object> mappings() {
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
extractHandlerMappings(this.handlerMappings, result);
|
||||
extractHandlerMappings(this.applicationContext, result);
|
||||
extractMethodMappings(this.methodMappings, result);
|
||||
extractMethodMappings(this.applicationContext, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected void extractMethodMappings(ApplicationContext applicationContext,
|
||||
Map<String, Object> result) {
|
||||
if (applicationContext != null) {
|
||||
for (Entry<String, AbstractHandlerMethodMapping> bean : applicationContext
|
||||
.getBeansOfType(AbstractHandlerMethodMapping.class).entrySet()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<?, HandlerMethod> methods = bean.getValue().getHandlerMethods();
|
||||
for (Entry<?, HandlerMethod> method : methods.entrySet()) {
|
||||
Map<String, String> map = new LinkedHashMap<>();
|
||||
map.put("bean", bean.getKey());
|
||||
map.put("method", method.getValue().toString());
|
||||
result.put(method.getKey().toString(), map);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void extractHandlerMappings(ApplicationContext applicationContext,
|
||||
Map<String, Object> result) {
|
||||
if (applicationContext != null) {
|
||||
Map<String, AbstractUrlHandlerMapping> mappings = applicationContext
|
||||
.getBeansOfType(AbstractUrlHandlerMapping.class);
|
||||
for (Entry<String, AbstractUrlHandlerMapping> mapping : mappings.entrySet()) {
|
||||
Map<String, Object> handlers = getHandlerMap(mapping.getValue());
|
||||
for (Entry<String, Object> handler : handlers.entrySet()) {
|
||||
result.put(handler.getKey(),
|
||||
Collections.singletonMap("bean", mapping.getKey()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> getHandlerMap(AbstractUrlHandlerMapping mapping) {
|
||||
if (AopUtils.isCglibProxy(mapping)) {
|
||||
// If the AbstractUrlHandlerMapping is a cglib proxy we can't call
|
||||
// the final getHandlerMap() method.
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return mapping.getHandlerMap();
|
||||
}
|
||||
|
||||
protected void extractHandlerMappings(
|
||||
Collection<AbstractUrlHandlerMapping> handlerMappings,
|
||||
Map<String, Object> result) {
|
||||
for (AbstractUrlHandlerMapping mapping : handlerMappings) {
|
||||
Map<String, Object> handlers = mapping.getHandlerMap();
|
||||
for (Map.Entry<String, Object> entry : handlers.entrySet()) {
|
||||
Class<? extends Object> handlerClass = entry.getValue().getClass();
|
||||
result.put(entry.getKey(),
|
||||
Collections.singletonMap("type", handlerClass.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void extractMethodMappings(
|
||||
Collection<AbstractHandlerMethodMapping<?>> methodMappings,
|
||||
Map<String, Object> result) {
|
||||
for (AbstractHandlerMethodMapping<?> mapping : methodMappings) {
|
||||
Map<?, HandlerMethod> methods = mapping.getHandlerMethods();
|
||||
for (Map.Entry<?, HandlerMethod> entry : methods.entrySet()) {
|
||||
result.put(String.valueOf(entry.getKey()), Collections
|
||||
.singletonMap("method", String.valueOf(entry.getValue())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.web.servlet;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link RequestMappingEndpoint}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(AbstractHandlerMethodMapping.class)
|
||||
public class RequestMappingEndpointAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnEnabledEndpoint
|
||||
public RequestMappingEndpoint requestMappingEndpoint() {
|
||||
return new RequestMappingEndpoint();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -41,10 +41,10 @@ org.springframework.boot.actuate.autoconfigure.system.DiskSpaceHealthIndicatorAu
|
||||
org.springframework.boot.actuate.autoconfigure.trace.TraceEndpointAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.trace.TraceRepositoryAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.trace.TraceWebFilterAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.web.MappingsEndpointAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.web.reactive.ReactiveManagementContextAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.web.servlet.RequestMappingEndpointAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration
|
||||
|
||||
org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration=\
|
||||
org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive.WebFluxEndpointManagementContextConfiguration,\
|
||||
|
||||
@@ -26,33 +26,26 @@ import java.util.stream.Stream;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive.WebFluxEndpointManagementContextConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.servlet.WebMvcEndpointManagementContextConfiguration;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.restdocs.JUnitRestDocumentation;
|
||||
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
|
||||
import org.springframework.restdocs.operation.preprocess.ContentModifyingOperationPreprocessor;
|
||||
import org.springframework.restdocs.operation.preprocess.OperationPreprocessor;
|
||||
import org.springframework.restdocs.payload.FieldDescriptor;
|
||||
import org.springframework.restdocs.payload.JsonFieldType;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
|
||||
@@ -62,30 +55,9 @@ import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWit
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(properties = { "spring.jackson.serialization.indent_output=true",
|
||||
@TestPropertySource(properties = { "spring.jackson.serialization.indent_output=true",
|
||||
"management.endpoints.web.expose=*" })
|
||||
public abstract class AbstractEndpointDocumentationTests {
|
||||
|
||||
@Rule
|
||||
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
|
||||
|
||||
protected MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext applicationContext;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.applicationContext)
|
||||
.apply(MockMvcRestDocumentation
|
||||
.documentationConfiguration(this.restDocumentation).uris())
|
||||
.build();
|
||||
}
|
||||
|
||||
protected WebApplicationContext getApplicationContext() {
|
||||
return this.applicationContext;
|
||||
}
|
||||
public class AbstractEndpointDocumentationTests {
|
||||
|
||||
protected String describeEnumValues(Class<? extends Enum<?>> enumType) {
|
||||
return StringUtils
|
||||
@@ -160,7 +132,9 @@ public abstract class AbstractEndpointDocumentationTests {
|
||||
DispatcherServletAutoConfiguration.class, EndpointAutoConfiguration.class,
|
||||
WebEndpointAutoConfiguration.class,
|
||||
WebMvcEndpointManagementContextConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class })
|
||||
WebFluxEndpointManagementContextConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class, WebFluxAutoConfiguration.class,
|
||||
HttpHandlerAutoConfiguration.class })
|
||||
static class BaseDocumentationConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class AuditEventsEndpointDocumentationTests
|
||||
extends AbstractEndpointDocumentationTests {
|
||||
extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
@MockBean
|
||||
private AuditEventRepository repository;
|
||||
|
||||
@@ -45,7 +45,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class BeansEndpointDocumentationTests extends AbstractEndpointDocumentationTests {
|
||||
public class BeansEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
@Test
|
||||
public void beans() throws Exception {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -51,7 +51,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class ConditionsReportEndpointDocumentationTests
|
||||
extends AbstractEndpointDocumentationTests {
|
||||
extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
@Rule
|
||||
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
|
||||
|
||||
@@ -38,7 +38,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class ConfigurationPropertiesReportEndpointDocumentationTests
|
||||
extends AbstractEndpointDocumentationTests {
|
||||
extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
@Test
|
||||
public void configProps() throws Exception {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -58,7 +58,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
*/
|
||||
@TestPropertySource(properties = "spring.config.location=classpath:/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/")
|
||||
public class EnvironmentEndpointDocumentationTests
|
||||
extends AbstractEndpointDocumentationTests {
|
||||
extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
private static final FieldDescriptor activeProfiles = fieldWithPath("activeProfiles")
|
||||
.description("Names of the active profiles, if any.");
|
||||
|
||||
@@ -45,7 +45,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@AutoConfigureTestDatabase
|
||||
public class FlywayEndpointDocumentationTests extends AbstractEndpointDocumentationTests {
|
||||
public class FlywayEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
@Test
|
||||
public void flyway() throws Exception {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -47,7 +47,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class HealthEndpointDocumentationTests extends AbstractEndpointDocumentationTests {
|
||||
public class HealthEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
@Test
|
||||
public void health() throws Exception {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -40,7 +40,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class HeapDumpWebEndpointDocumentationTests
|
||||
extends AbstractEndpointDocumentationTests {
|
||||
extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
@Test
|
||||
public void heapDump() throws Exception {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -44,7 +44,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class InfoEndpointDocumentationTests extends AbstractEndpointDocumentationTests {
|
||||
public class InfoEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
@Test
|
||||
public void info() throws Exception {
|
||||
|
||||
@@ -43,7 +43,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class LiquibaseEndpointDocumentationTests
|
||||
extends AbstractEndpointDocumentationTests {
|
||||
extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
@Test
|
||||
public void liquibase() throws Exception {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,7 +36,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
*/
|
||||
@TestPropertySource(properties = "logging.file=src/test/resources/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/sample.log")
|
||||
public class LogFileWebEndpointDocumentationTests
|
||||
extends AbstractEndpointDocumentationTests {
|
||||
extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
@Test
|
||||
public void logFile() throws Exception {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -49,7 +49,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class LoggersEndpointDocumentationTests
|
||||
extends AbstractEndpointDocumentationTests {
|
||||
extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
private static final List<FieldDescriptor> levelFields = Arrays.asList(
|
||||
fieldWithPath("configuredLevel")
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.endpoint.web.documentation;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.boot.actuate.web.MappingDescriptionProvider;
|
||||
import org.springframework.boot.actuate.web.MappingsEndpoint;
|
||||
import org.springframework.boot.actuate.web.reactive.DispatcherHandlersMappingDescriptionProvider;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.restdocs.JUnitRestDocumentation;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||
import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
|
||||
import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.documentationConfiguration;
|
||||
|
||||
/**
|
||||
* Tests for generating documentation describing {@link MappingsEndpoint}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.main.web-application-type=reactive")
|
||||
public class MappingsEndpointReactiveDocumentationTests
|
||||
extends AbstractEndpointDocumentationTests {
|
||||
|
||||
@Rule
|
||||
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
private WebTestClient client;
|
||||
|
||||
@Before
|
||||
public void webTestClient() {
|
||||
this.client = WebTestClient
|
||||
.bindToServer().filter(documentationConfiguration(this.restDocumentation)
|
||||
.snippets().withDefaults())
|
||||
.baseUrl("http://localhost:" + this.port).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappings() throws Exception {
|
||||
this.client.get().uri("/actuator/mappings").exchange().expectStatus().isOk()
|
||||
.expectBody()
|
||||
.consumeWith(document("mappings",
|
||||
responseFields(
|
||||
beneathPath("contexts.*.mappings.dispatcherHandlers")
|
||||
.withSubsectionId("dispatcher-handlers"),
|
||||
fieldWithPath("*").description(
|
||||
"Dispatcher handler mappings, if any, keyed by "
|
||||
+ "dispatcher handler bean name."),
|
||||
fieldWithPath("*.[].handler")
|
||||
.description("Handler for the mapping."),
|
||||
fieldWithPath("*.[].predicate")
|
||||
.description("Predicate for the mapping."))));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(BaseDocumentationConfiguration.class)
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
public NettyReactiveWebServerFactory netty() {
|
||||
return new NettyReactiveWebServerFactory(0);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DispatcherHandlersMappingDescriptionProvider dispatcherHandlersMappingDescriptionProvider() {
|
||||
return new DispatcherHandlersMappingDescriptionProvider();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MappingsEndpoint mappingsEndpoint(
|
||||
Collection<MappingDescriptionProvider> descriptionProviders,
|
||||
ConfigurableApplicationContext context) {
|
||||
return new MappingsEndpoint(descriptionProviders, context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.endpoint.web.documentation;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.boot.actuate.web.MappingDescriptionProvider;
|
||||
import org.springframework.boot.actuate.web.MappingsEndpoint;
|
||||
import org.springframework.boot.actuate.web.servlet.DispatcherServletsMappingDescriptionProvider;
|
||||
import org.springframework.boot.actuate.web.servlet.FiltersMappingDescriptionProvider;
|
||||
import org.springframework.boot.actuate.web.servlet.ServletsMappingDescriptionProvider;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.restdocs.JUnitRestDocumentation;
|
||||
import org.springframework.restdocs.payload.JsonFieldType;
|
||||
import org.springframework.restdocs.payload.ResponseFieldsSnippet;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
|
||||
import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
|
||||
import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.documentationConfiguration;
|
||||
|
||||
/**
|
||||
* Tests for generating documentation describing {@link MappingsEndpoint}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
public class MappingsEndpointServletDocumentationTests
|
||||
extends AbstractEndpointDocumentationTests {
|
||||
|
||||
@Rule
|
||||
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
private WebTestClient client;
|
||||
|
||||
@Before
|
||||
public void webTestClient() {
|
||||
this.client = WebTestClient.bindToServer()
|
||||
.filter(documentationConfiguration(this.restDocumentation))
|
||||
.baseUrl("http://localhost:" + this.port).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappings() throws Exception {
|
||||
ResponseFieldsSnippet commonResponseFields = responseFields(
|
||||
fieldWithPath("contexts")
|
||||
.description("Application contexts keyed by id."),
|
||||
fieldWithPath("contexts.*.mappings")
|
||||
.description("Mappings in the context, keyed by mapping type."),
|
||||
subsectionWithPath("contexts.*.mappings.dispatcherServlets")
|
||||
.description("Dispatcher servlet mappings, if any."),
|
||||
subsectionWithPath("contexts.*.mappings.servletFilters")
|
||||
.description("Servlet filter mappings, if any."),
|
||||
subsectionWithPath("contexts.*.mappings.servlets")
|
||||
.description("Servlet mappings, if any."),
|
||||
subsectionWithPath("contexts.*.mappings.dispatcherHandlers")
|
||||
.description("Dispatcher handler mappings, if any.").optional()
|
||||
.type(JsonFieldType.OBJECT),
|
||||
parentIdField());
|
||||
this.client.get().uri("/actuator/mappings").exchange().expectBody()
|
||||
.consumeWith(document("mappings", commonResponseFields,
|
||||
responseFields(
|
||||
beneathPath("contexts.*.mappings.dispatcherServlets")
|
||||
.withSubsectionId("dispatcher-servlets"),
|
||||
fieldWithPath("*").description(
|
||||
"Dispatcher servlet mappings, if any, keyed by "
|
||||
+ "dispatcher servlet bean name."),
|
||||
fieldWithPath("*.[].handler")
|
||||
.description("Handler for the mapping."),
|
||||
fieldWithPath("*.[].predicate")
|
||||
.description("Predicate for the mapping.")),
|
||||
responseFields(
|
||||
beneathPath("contexts.*.mappings.servletFilters")
|
||||
.withSubsectionId("servlet-filters"),
|
||||
fieldWithPath("[].servletNameMappings").description(
|
||||
"Names of the servlets to which the filter is mapped."),
|
||||
fieldWithPath("[].urlPatternMappings").description(
|
||||
"URL pattern to which the filter is mapped."),
|
||||
fieldWithPath("[].name")
|
||||
.description("Name of the filter."),
|
||||
fieldWithPath("[].className")
|
||||
.description("Class name of the filter")),
|
||||
responseFields(
|
||||
beneathPath("contexts.*.mappings.servlets")
|
||||
.withSubsectionId("servlets"),
|
||||
fieldWithPath("[].mappings")
|
||||
.description("Mappings of the servlet."),
|
||||
fieldWithPath("[].name")
|
||||
.description("Name of the servlet."),
|
||||
fieldWithPath("[].className")
|
||||
.description("Class name of the servlet"))));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(BaseDocumentationConfiguration.class)
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
public TomcatServletWebServerFactory tomcat() {
|
||||
return new TomcatServletWebServerFactory(0);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DispatcherServletsMappingDescriptionProvider dispatcherServletsMappingDescriptionProvider() {
|
||||
return new DispatcherServletsMappingDescriptionProvider();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServletsMappingDescriptionProvider servletsMappingDescriptionProvider() {
|
||||
return new ServletsMappingDescriptionProvider();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FiltersMappingDescriptionProvider filtersMappingDescriptionProvider() {
|
||||
return new FiltersMappingDescriptionProvider();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MappingsEndpoint mappingsEndpoint(
|
||||
Collection<MappingDescriptionProvider> descriptionProviders,
|
||||
ConfigurableApplicationContext context) {
|
||||
return new MappingsEndpoint(descriptionProviders, context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -40,7 +40,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class MetricsEndpointDocumentationTests
|
||||
extends AbstractEndpointDocumentationTests {
|
||||
extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
@Test
|
||||
public void metricNames() throws Exception {
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.endpoint.web.documentation;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.restdocs.JUnitRestDocumentation;
|
||||
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* Abstract base class for tests that generate endpoint documentation using Spring REST
|
||||
* Docs and {@link MockMvc}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(properties = { "spring.jackson.serialization.indent_output=true",
|
||||
"management.endpoints.web.expose=*" })
|
||||
public abstract class MockMvcEndpointDocumentationTests
|
||||
extends AbstractEndpointDocumentationTests {
|
||||
|
||||
@Rule
|
||||
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
|
||||
|
||||
protected MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext applicationContext;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.applicationContext)
|
||||
.apply(MockMvcRestDocumentation
|
||||
.documentationConfiguration(this.restDocumentation).uris())
|
||||
.build();
|
||||
}
|
||||
|
||||
protected WebApplicationContext getApplicationContext() {
|
||||
return this.applicationContext;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -38,7 +38,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class PrometheusScrapeEndpointDocumentationTests
|
||||
extends AbstractEndpointDocumentationTests {
|
||||
extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
@Test
|
||||
public void prometheus() throws Exception {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -44,7 +44,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class ScheduledTasksEndpointDocumentationTests
|
||||
extends AbstractEndpointDocumentationTests {
|
||||
extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
@Test
|
||||
public void scheduledTasks() throws Exception {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -55,7 +55,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
*/
|
||||
@TestPropertySource(properties = "spring.jackson.serialization.write-dates-as-timestamps=false")
|
||||
public class SessionsEndpointDocumentationTests
|
||||
extends AbstractEndpointDocumentationTests {
|
||||
extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
private static final Session sessionOne = createSession(
|
||||
Instant.now().minusSeconds(60 * 60 * 12), Instant.now().minusSeconds(45));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -37,7 +37,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class ShutdownEndpointDocumentationTests
|
||||
extends AbstractEndpointDocumentationTests {
|
||||
extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
@Test
|
||||
public void shutdown() throws Exception {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -38,7 +38,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class ThreadDumpEndpointDocumentationTests
|
||||
extends AbstractEndpointDocumentationTests {
|
||||
extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
@Test
|
||||
public void threadDump() throws Exception {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,7 +29,7 @@ import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoC
|
||||
import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.management.ThreadDumpEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.trace.TraceEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.servlet.RequestMappingEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.MappingsEndpointAutoConfiguration;
|
||||
|
||||
/**
|
||||
* A list of all endpoint auto-configuration classes for use in tests.
|
||||
@@ -50,7 +50,7 @@ final class EndpointAutoConfigurationClasses {
|
||||
all.add(InfoEndpointAutoConfiguration.class);
|
||||
all.add(ThreadDumpEndpointAutoConfiguration.class);
|
||||
all.add(TraceEndpointAutoConfiguration.class);
|
||||
all.add(RequestMappingEndpointAutoConfiguration.class);
|
||||
all.add(MappingsEndpointAutoConfiguration.class);
|
||||
ALL = all.toArray(new Class<?>[] {});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.web.servlet;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.EndpointInfo;
|
||||
import org.springframework.boot.actuate.endpoint.OperationType;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
|
||||
import org.springframework.boot.actuate.endpoint.web.OperationRequestPredicate;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointHttpMethod;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebOperation;
|
||||
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
|
||||
import org.springframework.boot.endpoint.web.EndpointMapping;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.context.annotation.ScopedProxyMode;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;
|
||||
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link RequestMappingEndpoint}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class RequestMappingEndpointTests {
|
||||
|
||||
private RequestMappingEndpoint endpoint = new RequestMappingEndpoint();
|
||||
|
||||
@Test
|
||||
public void concreteUrlMappings() {
|
||||
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
|
||||
mapping.setUrlMap(Collections.singletonMap("/foo", new Object()));
|
||||
mapping.setApplicationContext(new StaticApplicationContext());
|
||||
mapping.initApplicationContext();
|
||||
this.endpoint.setHandlerMappings(Collections.singletonList(mapping));
|
||||
Map<String, Object> result = this.endpoint.mappings();
|
||||
assertThat(result).hasSize(1);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) result.get("/foo");
|
||||
assertThat(map.get("type")).isEqualTo("java.lang.Object");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanUrlMappings() {
|
||||
StaticApplicationContext context = new StaticApplicationContext();
|
||||
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
|
||||
mapping.setUrlMap(Collections.singletonMap("/foo", new Object()));
|
||||
mapping.setApplicationContext(context);
|
||||
mapping.initApplicationContext();
|
||||
context.getDefaultListableBeanFactory().registerSingleton("mapping", mapping);
|
||||
this.endpoint.setApplicationContext(context);
|
||||
Map<String, Object> result = this.endpoint.mappings();
|
||||
assertThat(result).hasSize(1);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) result.get("/foo");
|
||||
assertThat(map.get("bean")).isEqualTo("mapping");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanUrlMappingsProxy() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
|
||||
MappingConfiguration.class);
|
||||
this.endpoint.setApplicationContext(context);
|
||||
Map<String, Object> result = this.endpoint.mappings();
|
||||
assertThat(result).hasSize(1);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) result.get("/foo");
|
||||
assertThat(map.get("bean")).isEqualTo("scopedTarget.mapping");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void beanMethodMappings() {
|
||||
StaticApplicationContext context = new StaticApplicationContext();
|
||||
context.getDefaultListableBeanFactory().registerSingleton("mapping",
|
||||
createHandlerMapping());
|
||||
this.endpoint.setApplicationContext(context);
|
||||
Map<String, Object> result = this.endpoint.mappings();
|
||||
assertThat(result).hasSize(2);
|
||||
assertThat(result.keySet()).filteredOn((key) -> key.contains("[/actuator/test]"))
|
||||
.hasOnlyOneElementSatisfying(
|
||||
(key) -> assertThat((Map<String, Object>) result.get(key))
|
||||
.containsOnlyKeys("bean", "method"));
|
||||
assertThat(result.keySet()).filteredOn((key) -> key.contains("[/actuator]"))
|
||||
.hasOnlyOneElementSatisfying(
|
||||
(key) -> assertThat((Map<String, Object>) result.get(key))
|
||||
.containsOnlyKeys("bean", "method"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void concreteMethodMappings() {
|
||||
WebMvcEndpointHandlerMapping mapping = createHandlerMapping();
|
||||
this.endpoint.setMethodMappings(Collections.singletonList(mapping));
|
||||
Map<String, Object> result = this.endpoint.mappings();
|
||||
assertThat(result).hasSize(2);
|
||||
assertThat(result.keySet()).filteredOn((key) -> key.contains("[/actuator/test]"))
|
||||
.hasOnlyOneElementSatisfying(
|
||||
(key) -> assertThat((Map<String, Object>) result.get(key))
|
||||
.containsOnlyKeys("method"));
|
||||
assertThat(result.keySet()).filteredOn((key) -> key.contains("[/actuator]"))
|
||||
.hasOnlyOneElementSatisfying(
|
||||
(key) -> assertThat((Map<String, Object>) result.get(key))
|
||||
.containsOnlyKeys("method"));
|
||||
}
|
||||
|
||||
private WebMvcEndpointHandlerMapping createHandlerMapping() {
|
||||
OperationRequestPredicate requestPredicate = new OperationRequestPredicate("test",
|
||||
WebEndpointHttpMethod.GET, Collections.singletonList("application/json"),
|
||||
Collections.singletonList("application/json"));
|
||||
WebOperation operation = new WebOperation(OperationType.READ,
|
||||
(arguments) -> "Invoked", true, requestPredicate, "test");
|
||||
WebMvcEndpointHandlerMapping mapping = new WebMvcEndpointHandlerMapping(
|
||||
new EndpointMapping("actuator"),
|
||||
Collections.singleton(new EndpointInfo<>("test", true,
|
||||
Collections.singleton(operation))),
|
||||
new EndpointMediaTypes(Arrays.asList("application/vnd.test+json"),
|
||||
Arrays.asList("application/vnd.test+json")));
|
||||
mapping.setApplicationContext(new StaticApplicationContext());
|
||||
mapping.afterPropertiesSet();
|
||||
return mapping;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class MappingConfiguration {
|
||||
|
||||
@Bean
|
||||
@Lazy
|
||||
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||
public AbstractUrlHandlerMapping mapping() {
|
||||
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
|
||||
mapping.setUrlMap(Collections.singletonMap("/foo", new Object()));
|
||||
return mapping;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -66,6 +66,17 @@
|
||||
<artifactId>jest</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.undertow</groupId>
|
||||
<artifactId>undertow-servlet</artifactId>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.cache</groupId>
|
||||
<artifactId>cache-api</artifactId>
|
||||
@@ -191,6 +202,11 @@
|
||||
<artifactId>spring-data-redis</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-rest-webmvc</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-solr</artifactId>
|
||||
@@ -281,22 +297,6 @@
|
||||
<artifactId>reactor-netty</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.undertow</groupId>
|
||||
<artifactId>undertow-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.undertow</groupId>
|
||||
<artifactId>undertow-servlet</artifactId>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.web;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* A {@link MappingDescriptionProvider} provides a {@link List} of mapping descriptions
|
||||
* via implementation-specific introspection of an application context.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public interface MappingDescriptionProvider {
|
||||
|
||||
/**
|
||||
* Returns the name of the mappings described by this provider.
|
||||
*
|
||||
* @return the name of the mappings
|
||||
*/
|
||||
String getMappingName();
|
||||
|
||||
/**
|
||||
* Produce the descriptions of the mappings identified by this provider in the given
|
||||
* {@code context}.
|
||||
* @param context the application context to introspect
|
||||
* @return the mapping descriptions
|
||||
*/
|
||||
Object describeMappings(ApplicationContext context);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.web;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* {@link Endpoint} to expose HTTP request mappings.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Endpoint(id = "mappings")
|
||||
public class MappingsEndpoint {
|
||||
|
||||
private final Collection<MappingDescriptionProvider> descriptionProviders;
|
||||
|
||||
private final ApplicationContext context;
|
||||
|
||||
public MappingsEndpoint(Collection<MappingDescriptionProvider> descriptionProviders,
|
||||
ApplicationContext context) {
|
||||
this.descriptionProviders = descriptionProviders;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public ApplicationMappings mappings() {
|
||||
ApplicationContext target = this.context;
|
||||
Map<String, ContextMappings> contextMappings = new HashMap<>();
|
||||
while (target != null) {
|
||||
contextMappings.put(target.getId(), mappingsForContext(target));
|
||||
target = target.getParent();
|
||||
}
|
||||
return new ApplicationMappings(contextMappings);
|
||||
}
|
||||
|
||||
private ContextMappings mappingsForContext(ApplicationContext applicationContext) {
|
||||
Map<String, Object> mappings = new HashMap<>();
|
||||
this.descriptionProviders
|
||||
.forEach((provider) -> mappings.put(provider.getMappingName(),
|
||||
provider.describeMappings(applicationContext)));
|
||||
return new ContextMappings(mappings, applicationContext.getParent() == null ? null
|
||||
: applicationContext.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* A description of an application's request mappings. Primarily intended for
|
||||
* serialization to JSON.
|
||||
*/
|
||||
public static final class ApplicationMappings {
|
||||
|
||||
private final Map<String, ContextMappings> contextMappings;
|
||||
|
||||
private ApplicationMappings(Map<String, ContextMappings> contextMappings) {
|
||||
this.contextMappings = contextMappings;
|
||||
}
|
||||
|
||||
public Map<String, ContextMappings> getContexts() {
|
||||
return this.contextMappings;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A description of an application context's request mappings. Primarily intended for
|
||||
* serialization to JSON.
|
||||
*/
|
||||
public static final class ContextMappings {
|
||||
|
||||
private final Map<String, Object> mappings;
|
||||
|
||||
private final String parentId;
|
||||
|
||||
private ContextMappings(Map<String, Object> mappings, String parentId) {
|
||||
this.mappings = mappings;
|
||||
this.parentId = parentId;
|
||||
}
|
||||
|
||||
public String getParentId() {
|
||||
return this.parentId;
|
||||
}
|
||||
|
||||
public Map<String, Object> getMappings() {
|
||||
return this.mappings;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.web.reactive;
|
||||
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
/**
|
||||
* A description of a mapping known to a {@link DispatcherServlet}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class DispatcherHandlerMappingDescription {
|
||||
|
||||
private final String predicate;
|
||||
|
||||
private final String handler;
|
||||
|
||||
DispatcherHandlerMappingDescription(String predicate, String handler) {
|
||||
this.predicate = predicate;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
public String getHandler() {
|
||||
return this.handler;
|
||||
}
|
||||
|
||||
public String getPredicate() {
|
||||
return this.predicate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.web.reactive;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.actuate.web.MappingDescriptionProvider;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.reactive.DispatcherHandler;
|
||||
import org.springframework.web.reactive.HandlerMapping;
|
||||
import org.springframework.web.reactive.function.server.HandlerFunction;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicate;
|
||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||
import org.springframework.web.reactive.function.server.RouterFunctions.Visitor;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.reactive.function.server.support.RouterFunctionMapping;
|
||||
import org.springframework.web.reactive.handler.AbstractUrlHandlerMapping;
|
||||
import org.springframework.web.reactive.result.method.RequestMappingInfo;
|
||||
import org.springframework.web.reactive.result.method.RequestMappingInfoHandlerMapping;
|
||||
import org.springframework.web.util.pattern.PathPattern;
|
||||
|
||||
/**
|
||||
* A {@link MappingDescriptionProvider} that introspects the {@link HandlerMapping
|
||||
* HandlerMappings} that are known to a {@link DispatcherHandler}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class DispatcherHandlersMappingDescriptionProvider
|
||||
implements MappingDescriptionProvider {
|
||||
|
||||
private static final List<HandlerMappingDescriptionProvider<? extends HandlerMapping>> descriptionProviders = Arrays
|
||||
.asList(new RequestMappingInfoHandlerMappingDescriptionProvider(),
|
||||
new UrlHandlerMappingDescriptionProvider(),
|
||||
new RouterFunctionMappingDescriptionProvider());
|
||||
|
||||
@Override
|
||||
public String getMappingName() {
|
||||
return "dispatcherHandlers";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<DispatcherHandlerMappingDescription>> describeMappings(
|
||||
ApplicationContext context) {
|
||||
Map<String, List<DispatcherHandlerMappingDescription>> mappings = new HashMap<>();
|
||||
context.getBeansOfType(DispatcherHandler.class).forEach(
|
||||
(name, handler) -> mappings.put(name, describeMappings(handler)));
|
||||
return mappings;
|
||||
}
|
||||
|
||||
private List<DispatcherHandlerMappingDescription> describeMappings(
|
||||
DispatcherHandler dispatcherHandler) {
|
||||
return dispatcherHandler.getHandlerMappings().stream().flatMap(this::describe)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T extends HandlerMapping> Stream<DispatcherHandlerMappingDescription> describe(
|
||||
T handlerMapping) {
|
||||
for (HandlerMappingDescriptionProvider<?> descriptionProvider : descriptionProviders) {
|
||||
if (descriptionProvider.getMappingClass().isInstance(handlerMapping)) {
|
||||
return ((HandlerMappingDescriptionProvider<T>) descriptionProvider)
|
||||
.describe(handlerMapping).stream();
|
||||
|
||||
}
|
||||
}
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
private interface HandlerMappingDescriptionProvider<T extends HandlerMapping> {
|
||||
|
||||
Class<T> getMappingClass();
|
||||
|
||||
List<DispatcherHandlerMappingDescription> describe(T handlerMapping);
|
||||
|
||||
}
|
||||
|
||||
private static final class RequestMappingInfoHandlerMappingDescriptionProvider
|
||||
implements
|
||||
HandlerMappingDescriptionProvider<RequestMappingInfoHandlerMapping> {
|
||||
|
||||
@Override
|
||||
public Class<RequestMappingInfoHandlerMapping> getMappingClass() {
|
||||
return RequestMappingInfoHandlerMapping.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DispatcherHandlerMappingDescription> describe(
|
||||
RequestMappingInfoHandlerMapping handlerMapping) {
|
||||
Map<RequestMappingInfo, HandlerMethod> handlerMethods = handlerMapping
|
||||
.getHandlerMethods();
|
||||
return handlerMethods.entrySet().stream().map(this::describe)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private DispatcherHandlerMappingDescription describe(
|
||||
Entry<RequestMappingInfo, HandlerMethod> mapping) {
|
||||
return new DispatcherHandlerMappingDescription(mapping.getKey().toString(),
|
||||
mapping.getValue().toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class UrlHandlerMappingDescriptionProvider
|
||||
implements HandlerMappingDescriptionProvider<AbstractUrlHandlerMapping> {
|
||||
|
||||
@Override
|
||||
public Class<AbstractUrlHandlerMapping> getMappingClass() {
|
||||
return AbstractUrlHandlerMapping.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DispatcherHandlerMappingDescription> describe(
|
||||
AbstractUrlHandlerMapping handlerMapping) {
|
||||
return handlerMapping.getHandlerMap().entrySet().stream().map(this::describe)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private DispatcherHandlerMappingDescription describe(
|
||||
Entry<PathPattern, Object> mapping) {
|
||||
return new DispatcherHandlerMappingDescription(
|
||||
mapping.getKey().getPatternString(), mapping.getValue().toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class RouterFunctionMappingDescriptionProvider
|
||||
implements HandlerMappingDescriptionProvider<RouterFunctionMapping> {
|
||||
|
||||
@Override
|
||||
public Class<RouterFunctionMapping> getMappingClass() {
|
||||
return RouterFunctionMapping.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DispatcherHandlerMappingDescription> describe(
|
||||
RouterFunctionMapping handlerMapping) {
|
||||
MappingDescriptionVisitor visitor = new MappingDescriptionVisitor();
|
||||
RouterFunction<?> routerFunction = handlerMapping.getRouterFunction();
|
||||
if (routerFunction != null) {
|
||||
routerFunction.accept(visitor);
|
||||
}
|
||||
return visitor.descriptions;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class MappingDescriptionVisitor implements Visitor {
|
||||
|
||||
private final List<DispatcherHandlerMappingDescription> descriptions = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void startNested(RequestPredicate predicate) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endNested(RequestPredicate predicate) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void route(RequestPredicate predicate,
|
||||
HandlerFunction<?> handlerFunction) {
|
||||
this.descriptions.add(new DispatcherHandlerMappingDescription(
|
||||
predicate.toString(), handlerFunction.toString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resources(Function<ServerRequest, Mono<Resource>> lookupFunction) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unknown(RouterFunction<?> routerFunction) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.web.servlet;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.apache.catalina.Container;
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.core.StandardWrapper;
|
||||
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
|
||||
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServer;
|
||||
import org.springframework.boot.web.server.WebServer;
|
||||
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
|
||||
/**
|
||||
* {@code DispatcherServletHandlerMappings} provides access to a {@link DispatcherServlet
|
||||
* DispatcherServlet's} handler mappings, triggering initialization of the dispatcher
|
||||
* servlet if necessary.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
final class DispatcherServletHandlerMappings {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final DispatcherServlet dispatcherServlet;
|
||||
|
||||
private final WebApplicationContext applicationContext;
|
||||
|
||||
DispatcherServletHandlerMappings(String name, DispatcherServlet dispatcherServlet,
|
||||
WebApplicationContext applicationContext) {
|
||||
this.name = name;
|
||||
this.dispatcherServlet = dispatcherServlet;
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public List<HandlerMapping> getHandlerMappings() {
|
||||
List<HandlerMapping> handlerMappings = this.dispatcherServlet
|
||||
.getHandlerMappings();
|
||||
if (handlerMappings == null) {
|
||||
initializeDispatcherServletIfPossible();
|
||||
handlerMappings = this.dispatcherServlet.getHandlerMappings();
|
||||
}
|
||||
return handlerMappings == null ? Collections.emptyList() : handlerMappings;
|
||||
}
|
||||
|
||||
private void initializeDispatcherServletIfPossible() {
|
||||
if (!(this.applicationContext instanceof ServletWebServerApplicationContext)) {
|
||||
return;
|
||||
}
|
||||
WebServer webServer = ((ServletWebServerApplicationContext) this.applicationContext)
|
||||
.getWebServer();
|
||||
if (webServer instanceof UndertowServletWebServer) {
|
||||
new UndertowServletInitializer((UndertowServletWebServer) webServer)
|
||||
.initializeServlet(this.name);
|
||||
}
|
||||
else if (webServer instanceof TomcatWebServer) {
|
||||
new TomcatServletInitializer((TomcatWebServer) webServer)
|
||||
.initializeServlet(this.name);
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
private static final class TomcatServletInitializer {
|
||||
|
||||
private final TomcatWebServer webServer;
|
||||
|
||||
private TomcatServletInitializer(TomcatWebServer webServer) {
|
||||
this.webServer = webServer;
|
||||
}
|
||||
|
||||
void initializeServlet(String name) {
|
||||
findContext().ifPresent((context) -> initializeServlet(context, name));
|
||||
}
|
||||
|
||||
private Optional<Context> findContext() {
|
||||
return Stream.of(this.webServer.getTomcat().getHost().findChildren())
|
||||
.filter(Context.class::isInstance).map(Context.class::cast)
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
private void initializeServlet(Context context, String name) {
|
||||
Container child = context.findChild(name);
|
||||
if (child instanceof StandardWrapper) {
|
||||
try {
|
||||
((StandardWrapper) child).allocate();
|
||||
}
|
||||
catch (ServletException ex) {
|
||||
// Continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class UndertowServletInitializer {
|
||||
|
||||
private final UndertowServletWebServer webServer;
|
||||
|
||||
private UndertowServletInitializer(UndertowServletWebServer webServer) {
|
||||
this.webServer = webServer;
|
||||
}
|
||||
|
||||
void initializeServlet(String name) {
|
||||
try {
|
||||
this.webServer.getDeploymentManager().getDeployment().getServlets()
|
||||
.getManagedServlet(name).forceInit();
|
||||
}
|
||||
catch (ServletException ex) {
|
||||
// Continue
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.web.servlet;
|
||||
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
/**
|
||||
* A description of a mapping known to a {@link DispatcherServlet}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class DispatcherServletMappingDescription {
|
||||
|
||||
private final String handler;
|
||||
|
||||
private final String predicate;
|
||||
|
||||
/**
|
||||
* Creates a new {@code DispatcherServletMappingDescription} for the given
|
||||
* {@code handler} that will receives requests that match the given {@code predicate}.
|
||||
*
|
||||
* @param predicate the predicate
|
||||
* @param handler the handler
|
||||
*/
|
||||
public DispatcherServletMappingDescription(String predicate, String handler) {
|
||||
this.handler = handler;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the handler for the described mapping.
|
||||
* @return the handler
|
||||
*/
|
||||
public String getHandler() {
|
||||
return this.handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the predicate for the described mapping.
|
||||
* @return the predicate
|
||||
*/
|
||||
public String getPredicate() {
|
||||
return this.predicate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.web.servlet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.boot.actuate.web.MappingDescriptionProvider;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.data.rest.webmvc.support.DelegatingHandlerMapping;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
|
||||
|
||||
/**
|
||||
* A {@link MappingDescriptionProvider} that introspects the {@link HandlerMapping
|
||||
* HandlerMappings} that are known to one or more {@link DispatcherServlet
|
||||
* DispatcherServlets}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class DispatcherServletsMappingDescriptionProvider
|
||||
implements MappingDescriptionProvider {
|
||||
|
||||
private static final List<HandlerMappingDescriptionProvider<? extends HandlerMapping>> descriptionProviders;
|
||||
|
||||
static {
|
||||
List<HandlerMappingDescriptionProvider<? extends HandlerMapping>> providers = new ArrayList<>();
|
||||
providers.add(new RequestMappingInfoHandlerMappingDescriptionProvider());
|
||||
providers.add(new UrlHandlerMappingDescriptionProvider());
|
||||
if (ClassUtils.isPresent(
|
||||
"org.springframework.data.rest.webmvc.support.DelegatingHandlerMapping",
|
||||
null)) {
|
||||
providers.add(new DelegatingHandlerMappingDescriptionProvider(
|
||||
new ArrayList<>(providers)));
|
||||
}
|
||||
descriptionProviders = Collections.unmodifiableList(providers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMappingName() {
|
||||
return "dispatcherServlets";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<DispatcherServletMappingDescription>> describeMappings(
|
||||
ApplicationContext context) {
|
||||
if (context instanceof WebApplicationContext) {
|
||||
return describeMappings((WebApplicationContext) context);
|
||||
}
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
private Map<String, List<DispatcherServletMappingDescription>> describeMappings(
|
||||
WebApplicationContext context) {
|
||||
Map<String, List<DispatcherServletMappingDescription>> mappings = new HashMap<>();
|
||||
context.getBeansOfType(DispatcherServlet.class)
|
||||
.forEach((name, dispatcherServlet) -> mappings.put(name,
|
||||
describeMappings(new DispatcherServletHandlerMappings(name,
|
||||
dispatcherServlet, context))));
|
||||
return mappings;
|
||||
}
|
||||
|
||||
private List<DispatcherServletMappingDescription> describeMappings(
|
||||
DispatcherServletHandlerMappings mappings) {
|
||||
return mappings.getHandlerMappings().stream().flatMap(this::describe)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private <T extends HandlerMapping> Stream<DispatcherServletMappingDescription> describe(
|
||||
T handlerMapping) {
|
||||
return describe(handlerMapping, descriptionProviders).stream();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T extends HandlerMapping> List<DispatcherServletMappingDescription> describe(
|
||||
T handlerMapping,
|
||||
List<HandlerMappingDescriptionProvider<?>> descriptionProviders) {
|
||||
for (HandlerMappingDescriptionProvider<?> descriptionProvider : descriptionProviders) {
|
||||
if (descriptionProvider.getMappingClass().isInstance(handlerMapping)) {
|
||||
return ((HandlerMappingDescriptionProvider<T>) descriptionProvider)
|
||||
.describe(handlerMapping);
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private interface HandlerMappingDescriptionProvider<T extends HandlerMapping> {
|
||||
|
||||
Class<T> getMappingClass();
|
||||
|
||||
List<DispatcherServletMappingDescription> describe(T handlerMapping);
|
||||
|
||||
}
|
||||
|
||||
private static final class RequestMappingInfoHandlerMappingDescriptionProvider
|
||||
implements
|
||||
HandlerMappingDescriptionProvider<RequestMappingInfoHandlerMapping> {
|
||||
|
||||
@Override
|
||||
public Class<RequestMappingInfoHandlerMapping> getMappingClass() {
|
||||
return RequestMappingInfoHandlerMapping.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DispatcherServletMappingDescription> describe(
|
||||
RequestMappingInfoHandlerMapping handlerMapping) {
|
||||
Map<RequestMappingInfo, HandlerMethod> handlerMethods = handlerMapping
|
||||
.getHandlerMethods();
|
||||
return handlerMethods.entrySet().stream().map(this::describe)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private DispatcherServletMappingDescription describe(
|
||||
Entry<RequestMappingInfo, HandlerMethod> mapping) {
|
||||
return new DispatcherServletMappingDescription(mapping.getKey().toString(),
|
||||
mapping.getValue().toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class UrlHandlerMappingDescriptionProvider
|
||||
implements HandlerMappingDescriptionProvider<AbstractUrlHandlerMapping> {
|
||||
|
||||
@Override
|
||||
public Class<AbstractUrlHandlerMapping> getMappingClass() {
|
||||
return AbstractUrlHandlerMapping.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DispatcherServletMappingDescription> describe(
|
||||
AbstractUrlHandlerMapping handlerMapping) {
|
||||
return handlerMapping.getHandlerMap().entrySet().stream().map(this::describe)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private DispatcherServletMappingDescription describe(
|
||||
Entry<String, Object> mapping) {
|
||||
return new DispatcherServletMappingDescription(mapping.getKey().toString(),
|
||||
mapping.getValue().toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class DelegatingHandlerMappingDescriptionProvider
|
||||
implements HandlerMappingDescriptionProvider<DelegatingHandlerMapping> {
|
||||
|
||||
private final List<HandlerMappingDescriptionProvider<?>> descriptionProviders;
|
||||
|
||||
private DelegatingHandlerMappingDescriptionProvider(
|
||||
List<HandlerMappingDescriptionProvider<?>> descriptionProviders) {
|
||||
this.descriptionProviders = descriptionProviders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<DelegatingHandlerMapping> getMappingClass() {
|
||||
return DelegatingHandlerMapping.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DispatcherServletMappingDescription> describe(
|
||||
DelegatingHandlerMapping handlerMapping) {
|
||||
List<DispatcherServletMappingDescription> descriptions = new ArrayList<>();
|
||||
for (HandlerMapping delegate : handlerMapping.getDelegates()) {
|
||||
descriptions.addAll(DispatcherServletsMappingDescriptionProvider
|
||||
.describe(delegate, this.descriptionProviders));
|
||||
}
|
||||
return descriptions;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.web.servlet;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.servlet.FilterRegistration;
|
||||
|
||||
/**
|
||||
* A {@link RegistrationMappingDescription} derived from a {@link FilterRegistration}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class FilterRegistrationMappingDescription
|
||||
extends RegistrationMappingDescription<FilterRegistration> {
|
||||
|
||||
/**
|
||||
* Creates a new {@code FilterRegistrationMappingDescription} derived from the given
|
||||
* {@code filterRegistration}.
|
||||
* @param filterRegistration the filter registration
|
||||
*/
|
||||
public FilterRegistrationMappingDescription(FilterRegistration filterRegistration) {
|
||||
super(filterRegistration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the servlet name mappings for the registered filter.
|
||||
*
|
||||
* @return the mappings
|
||||
*/
|
||||
public Collection<String> getServletNameMappings() {
|
||||
return this.getRegistration().getServletNameMappings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL pattern mappings for the registered filter.
|
||||
*
|
||||
* @return the mappings
|
||||
*/
|
||||
public Collection<String> getUrlPatternMappings() {
|
||||
return this.getRegistration().getUrlPatternMappings();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.web.servlet;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.boot.actuate.web.MappingDescriptionProvider;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* A {@link MappingDescriptionProvider} that describes that mappings of any {@link Filter
|
||||
* Filters} registered with a {@link ServletContext}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class FiltersMappingDescriptionProvider implements MappingDescriptionProvider {
|
||||
|
||||
@Override
|
||||
public List<FilterRegistrationMappingDescription> describeMappings(
|
||||
ApplicationContext context) {
|
||||
if (!(context instanceof WebApplicationContext)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return ((WebApplicationContext) context).getServletContext()
|
||||
.getFilterRegistrations().values().stream()
|
||||
.map(FilterRegistrationMappingDescription::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMappingName() {
|
||||
return "servletFilters";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.web.servlet;
|
||||
|
||||
import javax.servlet.Registration;
|
||||
|
||||
/**
|
||||
* A mapping description derived from a {@link Registration}.
|
||||
*
|
||||
* @param <T> type of the registration
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class RegistrationMappingDescription<T extends Registration> {
|
||||
|
||||
private final T registration;
|
||||
|
||||
/**
|
||||
* Creates a new {@link RegistrationMappingDescription} derived from the given
|
||||
* {@code registration} and with the given {@code predicate}.
|
||||
* @param registration the registration
|
||||
*/
|
||||
public RegistrationMappingDescription(T registration) {
|
||||
this.registration = registration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the registered Filter or Servlet.
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return this.registration.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class name of the registered Filter or Servlet.
|
||||
*
|
||||
* @return the class name
|
||||
*/
|
||||
public String getClassName() {
|
||||
return this.registration.getClassName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the registration that is being described.
|
||||
* @return the registration
|
||||
*/
|
||||
protected final T getRegistration() {
|
||||
return this.registration;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.web.servlet;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.servlet.ServletRegistration;
|
||||
|
||||
/**
|
||||
* A mapping description derived from a {@link ServletRegistration}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class ServletRegistrationMappingDescription
|
||||
extends RegistrationMappingDescription<ServletRegistration> {
|
||||
|
||||
/**
|
||||
* Creates a new {@code ServletRegistrationMappingDescription} derived from the given
|
||||
* {@code servletRegistration}.
|
||||
* @param servletRegistration the servlet registration
|
||||
*/
|
||||
public ServletRegistrationMappingDescription(
|
||||
ServletRegistration servletRegistration) {
|
||||
super(servletRegistration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mappings for the registered servlet.
|
||||
*
|
||||
* @return the mappings
|
||||
*/
|
||||
public Collection<String> getMappings() {
|
||||
return getRegistration().getMappings();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.web.servlet;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.boot.actuate.web.MappingDescriptionProvider;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* A {@link MappingDescriptionProvider} that describes that mappings of any {@link Servlet
|
||||
* Servlets} registered with a {@link ServletContext}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0
|
||||
*/
|
||||
public class ServletsMappingDescriptionProvider implements MappingDescriptionProvider {
|
||||
|
||||
@Override
|
||||
public List<ServletRegistrationMappingDescription> describeMappings(
|
||||
ApplicationContext context) {
|
||||
if (!(context instanceof WebApplicationContext)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return ((WebApplicationContext) context).getServletContext()
|
||||
.getServletRegistrations().values().stream()
|
||||
.map(ServletRegistrationMappingDescription::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMappingName() {
|
||||
return "servlets";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.web;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.servlet.FilterRegistration;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRegistration;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.actuate.web.MappingsEndpoint.ApplicationMappings;
|
||||
import org.springframework.boot.actuate.web.MappingsEndpoint.ContextMappings;
|
||||
import org.springframework.boot.actuate.web.reactive.DispatcherHandlerMappingDescription;
|
||||
import org.springframework.boot.actuate.web.reactive.DispatcherHandlersMappingDescriptionProvider;
|
||||
import org.springframework.boot.actuate.web.servlet.DispatcherServletMappingDescription;
|
||||
import org.springframework.boot.actuate.web.servlet.DispatcherServletsMappingDescriptionProvider;
|
||||
import org.springframework.boot.actuate.web.servlet.FilterRegistrationMappingDescription;
|
||||
import org.springframework.boot.actuate.web.servlet.FiltersMappingDescriptionProvider;
|
||||
import org.springframework.boot.actuate.web.servlet.ServletRegistrationMappingDescription;
|
||||
import org.springframework.boot.actuate.web.servlet.ServletsMappingDescriptionProvider;
|
||||
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.mock.web.MockServletConfig;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.reactive.config.EnableWebFlux;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicates;
|
||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||
import org.springframework.web.reactive.function.server.RouterFunctions;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link MappingsEndpoint}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class MappingsEndpointTests {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void servletWebMappings() {
|
||||
ServletContext servletContext = mock(ServletContext.class);
|
||||
given(servletContext.getInitParameterNames())
|
||||
.willReturn(new Vector<String>().elements());
|
||||
given(servletContext.getAttributeNames())
|
||||
.willReturn(new Vector<String>().elements());
|
||||
FilterRegistration filterRegistration = mock(FilterRegistration.class);
|
||||
given((Map<String, FilterRegistration>) servletContext.getFilterRegistrations())
|
||||
.willReturn(Collections.singletonMap("testFilter", filterRegistration));
|
||||
ServletRegistration servletRegistration = mock(ServletRegistration.class);
|
||||
given((Map<String, ServletRegistration>) servletContext.getServletRegistrations())
|
||||
.willReturn(Collections.singletonMap("testServlet", servletRegistration));
|
||||
WebApplicationContextRunner runner = new WebApplicationContextRunner(() -> {
|
||||
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
|
||||
context.setServletContext(servletContext);
|
||||
return context;
|
||||
}).withUserConfiguration(EndpointConfiguration.class,
|
||||
ServletWebConfiguration.class);
|
||||
runner.run((context) -> {
|
||||
ContextMappings contextMappings = contextMappings(context);
|
||||
assertThat(contextMappings.getParentId()).isNull();
|
||||
assertThat(contextMappings.getMappings())
|
||||
.containsOnlyKeys("dispatcherServlets", "servletFilters", "servlets");
|
||||
Map<String, List<DispatcherServletMappingDescription>> dispatcherServlets = mappings(
|
||||
contextMappings, "dispatcherServlets");
|
||||
assertThat(dispatcherServlets).containsOnlyKeys("dispatcherServlet");
|
||||
List<DispatcherServletMappingDescription> handlerMappings = dispatcherServlets
|
||||
.get("dispatcherServlet");
|
||||
assertThat(handlerMappings).hasSize(1);
|
||||
List<ServletRegistrationMappingDescription> servlets = mappings(
|
||||
contextMappings, "servlets");
|
||||
assertThat(servlets).hasSize(1);
|
||||
List<FilterRegistrationMappingDescription> filters = mappings(contextMappings,
|
||||
"servletFilters");
|
||||
assertThat(filters).hasSize(1);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reactiveWebMappings() {
|
||||
ReactiveWebApplicationContextRunner runner = new ReactiveWebApplicationContextRunner()
|
||||
.withUserConfiguration(EndpointConfiguration.class,
|
||||
ReactiveWebConfiguration.class);
|
||||
runner.run((context) -> {
|
||||
ContextMappings contextMappings = contextMappings(context);
|
||||
assertThat(contextMappings.getParentId()).isNull();
|
||||
assertThat(contextMappings.getMappings())
|
||||
.containsOnlyKeys("dispatcherHandlers");
|
||||
Map<String, List<DispatcherHandlerMappingDescription>> dispatcherHandlers = mappings(
|
||||
contextMappings, "dispatcherHandlers");
|
||||
assertThat(dispatcherHandlers).containsOnlyKeys("webHandler");
|
||||
List<DispatcherHandlerMappingDescription> handlerMappings = dispatcherHandlers
|
||||
.get("webHandler");
|
||||
assertThat(handlerMappings).hasSize(3);
|
||||
});
|
||||
}
|
||||
|
||||
private ContextMappings contextMappings(ApplicationContext context) {
|
||||
ApplicationMappings applicationMappings = context.getBean(MappingsEndpoint.class)
|
||||
.mappings();
|
||||
assertThat(applicationMappings.getContexts()).containsOnlyKeys(context.getId());
|
||||
return applicationMappings.getContexts().get(context.getId());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T mappings(ContextMappings contextMappings, String key) {
|
||||
return (T) contextMappings.getMappings().get(key);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class EndpointConfiguration {
|
||||
|
||||
@Bean
|
||||
public MappingsEndpoint mappingsEndpoint(
|
||||
Collection<MappingDescriptionProvider> descriptionProviders,
|
||||
ApplicationContext context) {
|
||||
return new MappingsEndpoint(descriptionProviders, context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebFlux
|
||||
@Controller
|
||||
static class ReactiveWebConfiguration {
|
||||
|
||||
@Bean
|
||||
public DispatcherHandlersMappingDescriptionProvider dispatcherHandlersMappingDescriptionProvider() {
|
||||
return new DispatcherHandlersMappingDescriptionProvider();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RouterFunction<ServerResponse> routerFunction() {
|
||||
return RouterFunctions
|
||||
.route(RequestPredicates.GET("/one"),
|
||||
(request) -> ServerResponse.ok().build())
|
||||
.andRoute(RequestPredicates.POST("/two"),
|
||||
(request) -> ServerResponse.ok().build());
|
||||
}
|
||||
|
||||
@RequestMapping("/three")
|
||||
public void three() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@Controller
|
||||
static class ServletWebConfiguration {
|
||||
|
||||
@Bean
|
||||
public DispatcherServletsMappingDescriptionProvider dispatcherServletsMappingDescriptionProvider() {
|
||||
return new DispatcherServletsMappingDescriptionProvider();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServletsMappingDescriptionProvider servletsMappingDescriptionProvider() {
|
||||
return new ServletsMappingDescriptionProvider();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FiltersMappingDescriptionProvider filtersMappingDescriptionProvider() {
|
||||
return new FiltersMappingDescriptionProvider();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DispatcherServlet dispatcherServlet(WebApplicationContext context)
|
||||
throws ServletException {
|
||||
DispatcherServlet dispatcherServlet = new DispatcherServlet(context);
|
||||
dispatcherServlet.init(new MockServletConfig());
|
||||
return dispatcherServlet;
|
||||
}
|
||||
|
||||
@RequestMapping("/three")
|
||||
public void three() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -168,6 +168,12 @@ public class UndertowServletWebServer implements WebServer {
|
||||
}
|
||||
}
|
||||
|
||||
public DeploymentManager getDeploymentManager() {
|
||||
synchronized (this.monitor) {
|
||||
return this.manager;
|
||||
}
|
||||
}
|
||||
|
||||
private void stopSilently() {
|
||||
try {
|
||||
if (this.undertow != null) {
|
||||
|
||||
Reference in New Issue
Block a user