From bbac4ea9fb5a49c9e8e2a38f424882c6bde04789 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Sun, 8 Dec 2013 15:46:12 +0000 Subject: [PATCH 01/10] @FrameworkEndpoint replaces EndpointHandlerAdapter --- .../EndpointWebMvcAutoConfiguration.java | 11 - ...dpointWebMvcChildContextConfiguration.java | 38 ++- .../actuate/endpoint/AbstractEndpoint.java | 32 --- .../AutoConfigurationReportEndpoint.java | 8 +- .../boot/actuate/endpoint/BeansEndpoint.java | 13 +- ...ConfigurationPropertiesReportEndpoint.java | 8 +- .../boot/actuate/endpoint/DumpEndpoint.java | 8 +- .../boot/actuate/endpoint/Endpoint.java | 13 - .../actuate/endpoint/EnvironmentEndpoint.java | 30 ++- .../boot/actuate/endpoint/HealthEndpoint.java | 12 +- .../boot/actuate/endpoint/InfoEndpoint.java | 8 +- .../actuate/endpoint/JolokiaEndpoint.java | 8 +- .../endpoint/ManagementErrorEndpoint.java | 54 ++++ .../actuate/endpoint/MetricsEndpoint.java | 29 ++- .../actuate/endpoint/ShutdownEndpoint.java | 15 +- .../boot/actuate/endpoint/TraceEndpoint.java | 8 +- .../endpoint/mvc/EndpointHandlerAdapter.java | 238 ------------------ .../endpoint/mvc/EndpointHandlerMapping.java | 123 +++++---- .../endpoint/mvc/FrameworkEndpoint.java | 34 +++ .../actuate/web/BasicErrorController.java | 2 +- .../EndpointWebMvcAutoConfigurationTests.java | 27 +- .../endpoint/AbstractEndpointTests.java | 11 +- .../actuate/endpoint/BeansEndpointTests.java | 5 +- .../mvc/EndpointHandlerAdapterTests.java | 74 ------ .../mvc/EndpointHandlerMappingTests.java | 118 ++++++--- .../BasicErrorControllerIntegrationTests.java | 5 +- ...rrorControllerSpecialIntegrationTests.java | 22 +- 27 files changed, 425 insertions(+), 529 deletions(-) create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ManagementErrorEndpoint.java delete mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerAdapter.java create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/FrameworkEndpoint.java delete mode 100644 spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerAdapterTests.java diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java index 895f8f2a515..3e46e0e1103 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java @@ -29,7 +29,6 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.endpoint.Endpoint; -import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerAdapter; import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping; import org.springframework.boot.actuate.properties.ManagementServerProperties; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -40,7 +39,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration; import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration; -import org.springframework.boot.autoconfigure.web.HttpMessageConverters; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext; @@ -91,15 +89,6 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware, return mapping; } - @Bean - @ConditionalOnMissingBean - public EndpointHandlerAdapter endpointHandlerAdapter( - final HttpMessageConverters messageConverters) { - EndpointHandlerAdapter adapter = new EndpointHandlerAdapter(); - adapter.setMessageConverters(messageConverters.getConverters()); - return adapter; - } - @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java index cb37692695e..5d255ba854b 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java @@ -16,8 +16,6 @@ package org.springframework.boot.actuate.autoconfigure; -import java.util.Map; - import javax.servlet.Filter; import org.springframework.beans.factory.BeanFactory; @@ -26,9 +24,7 @@ import org.springframework.beans.factory.HierarchicalBeanFactory; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.actuate.endpoint.AbstractEndpoint; -import org.springframework.boot.actuate.endpoint.Endpoint; -import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerAdapter; +import org.springframework.boot.actuate.endpoint.ManagementErrorEndpoint; import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping; import org.springframework.boot.actuate.properties.ManagementServerProperties; import org.springframework.boot.actuate.web.ErrorController; @@ -42,11 +38,11 @@ import org.springframework.boot.context.embedded.ErrorPage; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.web.context.request.RequestAttributes; -import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.client.RestTemplate; import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.HandlerAdapter; import org.springframework.web.servlet.HandlerMapping; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; /** * Configuration triggered from {@link EndpointWebMvcAutoConfiguration} when a new @@ -57,6 +53,9 @@ import org.springframework.web.servlet.HandlerMapping; @Configuration public class EndpointWebMvcChildContextConfiguration { + @Value("${error.path:/error}") + private String errorPath = "/error"; + @Configuration protected static class ServerCustomization implements EmbeddedServletContainerCustomizer { @@ -100,13 +99,19 @@ public class EndpointWebMvcChildContextConfiguration { } @Bean - public HandlerMapping handlerMapping() { - return new EndpointHandlerMapping(); + public HandlerAdapter handlerAdapter() { + // TODO: maybe this needs more configuration for non-basic response use cases + RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter(); + adapter.setMessageConverters(new RestTemplate().getMessageConverters()); + return adapter; } @Bean - public HandlerAdapter handlerAdapter() { - return new EndpointHandlerAdapter(); + public HandlerMapping handlerMapping() { + EndpointHandlerMapping mapping = new EndpointHandlerMapping(); + // In a child context we definitely want to see the parent endpoints + mapping.setDetectHandlerMethodsInAncestorContexts(true); + return mapping; } /* @@ -116,15 +121,8 @@ public class EndpointWebMvcChildContextConfiguration { * endpoints. */ @Bean - public Endpoint> errorEndpoint(final ErrorController controller) { - return new AbstractEndpoint>("/error", false, true) { - @Override - protected Map doInvoke() { - RequestAttributes attributes = RequestContextHolder - .currentRequestAttributes(); - return controller.extract(attributes, false); - } - }; + public ManagementErrorEndpoint errorEndpoint(final ErrorController controller) { + return new ManagementErrorEndpoint(this.errorPath, controller); } @Configuration diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AbstractEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AbstractEndpoint.java index dff785b980d..221bd36c714 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AbstractEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AbstractEndpoint.java @@ -19,28 +19,15 @@ package org.springframework.boot.actuate.endpoint; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; - /** * Abstract base for {@link Endpoint} implementations. *

- * {@link Endpoint}s that support other {@link HttpMethod}s than {@link HttpMethod#GET} - * should override {@link #methods()} and provide a list of supported methods. * * @author Phillip Webb * @author Christian Dupuis */ public abstract class AbstractEndpoint implements Endpoint { - private static final MediaType[] NO_MEDIA_TYPES = new MediaType[0]; - - protected static final HttpMethod[] NO_HTTP_METHOD = new HttpMethod[0]; - - protected static final HttpMethod[] GET_HTTP_METHOD = new HttpMethod[] { HttpMethod.GET }; - - protected static final HttpMethod[] POST_HTTP_METHOD = new HttpMethod[] { HttpMethod.POST }; - @NotNull @Pattern(regexp = "/[^/]*", message = "Path must start with /") private String path; @@ -85,23 +72,4 @@ public abstract class AbstractEndpoint implements Endpoint { this.sensitive = sensitive; } - @Override - public MediaType[] produces() { - return NO_MEDIA_TYPES; - } - - @Override - public HttpMethod[] methods() { - return GET_HTTP_METHOD; - } - - @Override - public final T invoke() { - if (this.enabled) { - return doInvoke(); - } - throw new EndpointDisabledException(); - } - - protected abstract T doInvoke(); } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpoint.java index a6445182ee3..a10237be0b8 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpoint.java @@ -21,6 +21,7 @@ import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.endpoint.AutoConfigurationReportEndpoint.Report; +import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; import org.springframework.boot.autoconfigure.AutoConfigurationReport; import org.springframework.boot.autoconfigure.AutoConfigurationReport.ConditionAndOutcome; import org.springframework.boot.autoconfigure.AutoConfigurationReport.ConditionAndOutcomes; @@ -31,6 +32,8 @@ import org.springframework.util.ClassUtils; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; import com.fasterxml.jackson.annotation.JsonPropertyOrder; @@ -42,6 +45,7 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder; * @author Dave Syer */ @ConfigurationProperties(name = "endpoints.autoconfig", ignoreUnknownFields = false) +@FrameworkEndpoint public class AutoConfigurationReportEndpoint extends AbstractEndpoint { @Autowired @@ -52,7 +56,9 @@ public class AutoConfigurationReportEndpoint extends AbstractEndpoint { } @Override - protected Report doInvoke() { + @RequestMapping + @ResponseBody + public Report invoke() { return new Report(this.autoConfigurationReport); } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/BeansEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/BeansEndpoint.java index 6ee2000f30c..b07f3c9408a 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/BeansEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/BeansEndpoint.java @@ -17,12 +17,15 @@ package org.springframework.boot.actuate.endpoint; import org.springframework.beans.BeansException; +import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.support.LiveBeansView; import org.springframework.core.env.Environment; import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; /** * Exposes JSON view of Spring beans. If the {@link Environment} contains a key setting @@ -33,6 +36,7 @@ import org.springframework.http.MediaType; * @author Dave Syer */ @ConfigurationProperties(name = "endpoints.beans", ignoreUnknownFields = false) +@FrameworkEndpoint public class BeansEndpoint extends AbstractEndpoint implements ApplicationContextAware { @@ -51,12 +55,9 @@ public class BeansEndpoint extends AbstractEndpoint implements } @Override - public MediaType[] produces() { - return new MediaType[] { MediaType.APPLICATION_JSON }; - } - - @Override - protected String doInvoke() { + @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public String invoke() { return this.liveBeansView.getSnapshotAsJson(); } } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java index d2f4c1b8c89..fca2a4eea4c 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java @@ -19,10 +19,13 @@ package org.springframework.boot.actuate.endpoint; import java.util.Map; import org.springframework.beans.BeansException; +import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.util.Assert; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; import com.fasterxml.jackson.databind.ObjectMapper; @@ -37,6 +40,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; * @author Christian Dupuis */ @ConfigurationProperties(name = "endpoints.configprops", ignoreUnknownFields = false) +@FrameworkEndpoint public class ConfigurationPropertiesReportEndpoint extends AbstractEndpoint> implements ApplicationContextAware { @@ -64,7 +68,9 @@ public class ConfigurationPropertiesReportEndpoint extends @Override @SuppressWarnings("unchecked") - protected Map doInvoke() { + @RequestMapping + @ResponseBody + public Map invoke() { Map beans = this.context .getBeansWithAnnotation(ConfigurationProperties.class); diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/DumpEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/DumpEndpoint.java index 15fbc55e27f..33d7f72a83b 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/DumpEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/DumpEndpoint.java @@ -21,7 +21,10 @@ import java.lang.management.ThreadInfo; import java.util.Arrays; import java.util.List; +import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; /** * {@link Endpoint} to expose thread info. @@ -29,6 +32,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * @author Dave Syer */ @ConfigurationProperties(name = "endpoints.dump", ignoreUnknownFields = false) +@FrameworkEndpoint public class DumpEndpoint extends AbstractEndpoint> { /** @@ -39,7 +43,9 @@ public class DumpEndpoint extends AbstractEndpoint> { } @Override - protected List doInvoke() { + @RequestMapping + @ResponseBody + public List invoke() { return Arrays.asList(ManagementFactory.getThreadMXBean().dumpAllThreads(true, true)); } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Endpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Endpoint.java index 7fe94e4ecdd..6a541238922 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Endpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Endpoint.java @@ -16,9 +16,6 @@ package org.springframework.boot.actuate.endpoint; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; - /** * An endpoint that can be used to expose useful information to operations. Usually * exposed via Spring MVC but could also be exposed using some other technique. @@ -41,16 +38,6 @@ public interface Endpoint { */ boolean isSensitive(); - /** - * Returns the {@link MediaType}s that this endpoint produces or {@code null}. - */ - MediaType[] produces(); - - /** - * Returns the {@link HttpMethod}s that this endpoint supports. - */ - HttpMethod[] methods(); - /** * Called to invoke the endpoint. * @return the results of the invocation diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpoint.java index 1e0e8d600b8..a176d150d67 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpoint.java @@ -19,6 +19,7 @@ package org.springframework.boot.actuate.endpoint; import java.util.LinkedHashMap; import java.util.Map; +import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.EnvironmentAware; import org.springframework.core.env.ConfigurableEnvironment; @@ -26,6 +27,11 @@ import org.springframework.core.env.EnumerablePropertySource; import org.springframework.core.env.Environment; import org.springframework.core.env.PropertySource; import org.springframework.core.env.StandardEnvironment; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; /** * {@link Endpoint} to expose {@link ConfigurableEnvironment environment} information. @@ -34,6 +40,7 @@ import org.springframework.core.env.StandardEnvironment; * @author Phillip Webb */ @ConfigurationProperties(name = "endpoints.env", ignoreUnknownFields = false) +@FrameworkEndpoint public class EnvironmentEndpoint extends AbstractEndpoint> implements EnvironmentAware { @@ -47,7 +54,9 @@ public class EnvironmentEndpoint extends AbstractEndpoint> i } @Override - protected Map doInvoke() { + @RequestMapping + @ResponseBody + public Map invoke() { Map result = new LinkedHashMap(); result.put("profiles", this.environment.getActiveProfiles()); for (PropertySource source : getPropertySources()) { @@ -63,6 +72,16 @@ public class EnvironmentEndpoint extends AbstractEndpoint> i return result; } + @RequestMapping("/{name:.*}") + @ResponseBody + public Object value(@PathVariable String name) { + String result = this.environment.getProperty(name); + if (result == null) { + throw new NoSuchPropertyException("No such property: " + name); + } + return sanitize(name, result); + } + private Iterable> getPropertySources() { if (this.environment != null && this.environment instanceof ConfigurableEnvironment) { @@ -84,4 +103,13 @@ public class EnvironmentEndpoint extends AbstractEndpoint> i this.environment = environment; } + @ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "No such property") + public static class NoSuchPropertyException extends RuntimeException { + + public NoSuchPropertyException(String string) { + super(string); + } + + } + } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/HealthEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/HealthEndpoint.java index 9863bc6243d..4ee546a542f 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/HealthEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/HealthEndpoint.java @@ -16,9 +16,12 @@ package org.springframework.boot.actuate.endpoint; +import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.util.Assert; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; /** * {@link Endpoint} to expose application health. @@ -26,6 +29,7 @@ import org.springframework.util.Assert; * @author Dave Syer */ @ConfigurationProperties(name = "endpoints.health", ignoreUnknownFields = false) +@FrameworkEndpoint public class HealthEndpoint extends AbstractEndpoint { private HealthIndicator indicator; @@ -41,8 +45,14 @@ public class HealthEndpoint extends AbstractEndpoint { this.indicator = indicator; } + HealthEndpoint() { + super("/health", false, true); + } + @Override - protected T doInvoke() { + @RequestMapping + @ResponseBody + public T invoke() { return this.indicator.health(); } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java index 06ae714086f..27fc113ece7 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java @@ -20,8 +20,11 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; +import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.util.Assert; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; /** * {@link Endpoint} to expose arbitrary application information. @@ -29,6 +32,7 @@ import org.springframework.util.Assert; * @author Dave Syer */ @ConfigurationProperties(name = "endpoints.info", ignoreUnknownFields = false) +@FrameworkEndpoint public class InfoEndpoint extends AbstractEndpoint> { private Map info; @@ -45,7 +49,9 @@ public class InfoEndpoint extends AbstractEndpoint> { } @Override - protected Map doInvoke() { + @RequestMapping + @ResponseBody + public Map invoke() { Map info = new LinkedHashMap(this.info); info.putAll(getAdditionalInfo()); return info; diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/JolokiaEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/JolokiaEndpoint.java index fbdc991c278..9d394087991 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/JolokiaEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/JolokiaEndpoint.java @@ -17,7 +17,6 @@ package org.springframework.boot.actuate.endpoint; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.http.HttpMethod; /** * {@link Endpoint} implementation to register the Jolokia infrastructure with the Boot @@ -33,13 +32,8 @@ public class JolokiaEndpoint extends AbstractEndpoint { } @Override - protected String doInvoke() { + public String invoke() { return null; } - @Override - public HttpMethod[] methods() { - return NO_HTTP_METHOD; - } - } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ManagementErrorEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ManagementErrorEndpoint.java new file mode 100644 index 00000000000..c7e57455246 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ManagementErrorEndpoint.java @@ -0,0 +1,54 @@ +/* + * Copyright 2012-2013 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.endpoint; + +import java.util.Map; + +import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; +import org.springframework.boot.actuate.web.ErrorController; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; + +/** + * Special endpoint for handling "/error" path when the management servlet is in a child + * context. The regular {@link ErrorController} should be available there but because of + * the way the handler mappings are set up it will not be detected. + * + * @author Dave Syer + */ +@FrameworkEndpoint +@ConfigurationProperties(name = "error") +public class ManagementErrorEndpoint extends AbstractEndpoint> { + + private final ErrorController controller; + + public ManagementErrorEndpoint(String path, ErrorController controller) { + super(path, false, true); + this.controller = controller; + } + + @Override + @RequestMapping + @ResponseBody + public Map invoke() { + RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); + return this.controller.extract(attributes, false); + } +} \ No newline at end of file diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/MetricsEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/MetricsEndpoint.java index 47f82346550..3e0b30331e7 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/MetricsEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/MetricsEndpoint.java @@ -19,9 +19,15 @@ package org.springframework.boot.actuate.endpoint; import java.util.LinkedHashMap; import java.util.Map; +import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; import org.springframework.boot.actuate.metrics.Metric; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.http.HttpStatus; import org.springframework.util.Assert; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; /** * {@link Endpoint} to expose {@link PublicMetrics}. @@ -29,6 +35,7 @@ import org.springframework.util.Assert; * @author Dave Syer */ @ConfigurationProperties(name = "endpoints.metrics", ignoreUnknownFields = false) +@FrameworkEndpoint public class MetricsEndpoint extends AbstractEndpoint> { private PublicMetrics metrics; @@ -45,7 +52,9 @@ public class MetricsEndpoint extends AbstractEndpoint> { } @Override - protected Map doInvoke() { + @RequestMapping + @ResponseBody + public Map invoke() { Map result = new LinkedHashMap(); for (Metric metric : this.metrics.metrics()) { result.put(metric.getName(), metric.getValue()); @@ -53,4 +62,22 @@ public class MetricsEndpoint extends AbstractEndpoint> { return result; } + @RequestMapping("/{name:.*}") + @ResponseBody + public Object value(@PathVariable String name) { + Object value = invoke().get(name); + if (value == null) { + throw new NoSuchMetricException("No such metric: " + name); + } + return value; + } + + @ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "No such metric") + public static class NoSuchMetricException extends RuntimeException { + + public NoSuchMetricException(String string) { + super(string); + } + + } } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ShutdownEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ShutdownEndpoint.java index fc7be0a833e..9585a799efb 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ShutdownEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ShutdownEndpoint.java @@ -20,11 +20,14 @@ import java.util.Collections; import java.util.Map; import org.springframework.beans.BeansException; +import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.http.HttpMethod; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; /** * {@link Endpoint} to shutdown the {@link ApplicationContext}. @@ -33,6 +36,7 @@ import org.springframework.http.HttpMethod; * @author Christian Dupuis */ @ConfigurationProperties(name = "endpoints.shutdown", ignoreUnknownFields = false) +@FrameworkEndpoint public class ShutdownEndpoint extends AbstractEndpoint> implements ApplicationContextAware { @@ -46,7 +50,9 @@ public class ShutdownEndpoint extends AbstractEndpoint> impl } @Override - protected Map doInvoke() { + @RequestMapping(method = RequestMethod.POST) + @ResponseBody + public Map invoke() { if (this.context == null) { return Collections. singletonMap("message", @@ -77,9 +83,4 @@ public class ShutdownEndpoint extends AbstractEndpoint> impl } } - @Override - public HttpMethod[] methods() { - return POST_HTTP_METHOD; - } - } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/TraceEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/TraceEndpoint.java index d21f4acd0b2..a003170af8f 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/TraceEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/TraceEndpoint.java @@ -18,10 +18,13 @@ package org.springframework.boot.actuate.endpoint; import java.util.List; +import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; import org.springframework.boot.actuate.trace.Trace; import org.springframework.boot.actuate.trace.TraceRepository; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.util.Assert; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; /** * {@link Endpoint} to expose {@link Trace} information. @@ -29,6 +32,7 @@ import org.springframework.util.Assert; * @author Dave Syer */ @ConfigurationProperties(name = "endpoints.trace", ignoreUnknownFields = false) +@FrameworkEndpoint public class TraceEndpoint extends AbstractEndpoint> { private TraceRepository repository; @@ -45,7 +49,9 @@ public class TraceEndpoint extends AbstractEndpoint> { } @Override - protected List doInvoke() { + @RequestMapping + @ResponseBody + public List invoke() { return this.repository.findAll(); } } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerAdapter.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerAdapter.java deleted file mode 100644 index debd78158b6..00000000000 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerAdapter.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright 2012-2013 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.endpoint.mvc; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.boot.actuate.endpoint.Endpoint; -import org.springframework.boot.actuate.endpoint.EndpointDisabledException; -import org.springframework.http.MediaType; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.http.server.ServletServerHttpResponse; -import org.springframework.web.HttpMediaTypeNotAcceptableException; -import org.springframework.web.accept.ContentNegotiationManager; -import org.springframework.web.context.request.ServletWebRequest; -import org.springframework.web.servlet.HandlerAdapter; -import org.springframework.web.servlet.ModelAndView; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; -import org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor; -import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException; - -import com.fasterxml.jackson.databind.SerializationFeature; - -/** - * MVC {@link HandlerAdapter} for {@link Endpoint}s. Similar in may respects to - * {@link AbstractMessageConverterMethodProcessor} but not tied to annotated methods. - * - * @author Phillip Webb - * - * @see EndpointHandlerMapping - */ -public final class EndpointHandlerAdapter implements HandlerAdapter { - - private final Log logger = LogFactory.getLog(getClass()); - - private static final MediaType MEDIA_TYPE_APPLICATION = new MediaType("application"); - - private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager(); - - private List> messageConverters; - - private List allSupportedMediaTypes; - - public EndpointHandlerAdapter() { - WebMvcConfigurationSupportConventions conventions = new WebMvcConfigurationSupportConventions(); - setMessageConverters(conventions.getDefaultHttpMessageConverters()); - } - - @Override - public boolean supports(Object handler) { - return handler instanceof Endpoint; - } - - @Override - public long getLastModified(HttpServletRequest request, Object handler) { - return -1; - } - - @Override - public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, - Object handler) throws Exception { - handle(request, response, (Endpoint) handler); - return null; - } - - @SuppressWarnings("unchecked") - private void handle(HttpServletRequest request, HttpServletResponse response, - Endpoint endpoint) throws Exception { - - Object result = null; - try { - result = endpoint.invoke(); - } - catch (EndpointDisabledException e) { - // Disabled endpoints should get mapped to a HTTP 404 - throw new NoSuchRequestHandlingMethodException(request); - } - - Class resultClass = result.getClass(); - - List mediaTypes = getMediaTypes(request, endpoint, resultClass); - MediaType selectedMediaType = selectMediaType(mediaTypes); - - ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response); - try { - if (selectedMediaType != null) { - selectedMediaType = selectedMediaType.removeQualityValue(); - for (HttpMessageConverter messageConverter : this.messageConverters) { - if (messageConverter.canWrite(resultClass, selectedMediaType)) { - ((HttpMessageConverter) messageConverter).write(result, - selectedMediaType, outputMessage); - if (this.logger.isDebugEnabled()) { - this.logger.debug("Written [" + result + "] as \"" - + selectedMediaType + "\" using [" + messageConverter - + "]"); - } - return; - } - } - } - throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes); - } - finally { - outputMessage.close(); - } - } - - private List getMediaTypes(HttpServletRequest request, - Endpoint endpoint, Class resultClass) - throws HttpMediaTypeNotAcceptableException { - List requested = getAcceptableMediaTypes(request); - List producible = getProducibleMediaTypes(endpoint, resultClass); - - Set compatible = new LinkedHashSet(); - for (MediaType r : requested) { - for (MediaType p : producible) { - if (r.isCompatibleWith(p)) { - compatible.add(getMostSpecificMediaType(r, p)); - } - } - } - if (compatible.isEmpty()) { - throw new HttpMediaTypeNotAcceptableException(producible); - } - List mediaTypes = new ArrayList(compatible); - MediaType.sortBySpecificityAndQuality(mediaTypes); - return mediaTypes; - } - - private List getAcceptableMediaTypes(HttpServletRequest request) - throws HttpMediaTypeNotAcceptableException { - List mediaTypes = this.contentNegotiationManager - .resolveMediaTypes(new ServletWebRequest(request)); - return mediaTypes.isEmpty() ? Collections.singletonList(MediaType.ALL) - : mediaTypes; - } - - private List getProducibleMediaTypes(Endpoint endpoint, - Class returnValueClass) { - MediaType[] mediaTypes = endpoint.produces(); - if (mediaTypes != null && mediaTypes.length != 0) { - return Arrays.asList(mediaTypes); - } - - if (this.allSupportedMediaTypes.isEmpty()) { - return Collections.singletonList(MediaType.ALL); - } - - List result = new ArrayList(); - for (HttpMessageConverter converter : this.messageConverters) { - if (converter.canWrite(returnValueClass, null)) { - result.addAll(converter.getSupportedMediaTypes()); - } - } - return result; - } - - private MediaType getMostSpecificMediaType(MediaType acceptType, MediaType produceType) { - produceType = produceType.copyQualityValue(acceptType); - return MediaType.SPECIFICITY_COMPARATOR.compare(acceptType, produceType) <= 0 ? acceptType - : produceType; - } - - private MediaType selectMediaType(List mediaTypes) { - MediaType selectedMediaType = null; - for (MediaType mediaType : mediaTypes) { - if (mediaType.isConcrete()) { - selectedMediaType = mediaType; - break; - } - else if (mediaType.equals(MediaType.ALL) - || mediaType.equals(MEDIA_TYPE_APPLICATION)) { - selectedMediaType = MediaType.APPLICATION_OCTET_STREAM; - break; - } - } - return selectedMediaType; - } - - public void setContentNegotiationManager( - ContentNegotiationManager contentNegotiationManager) { - this.contentNegotiationManager = contentNegotiationManager; - } - - public void setMessageConverters(List> messageConverters) { - this.messageConverters = messageConverters; - Set allSupportedMediaTypes = new LinkedHashSet(); - for (HttpMessageConverter messageConverter : messageConverters) { - allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes()); - } - this.allSupportedMediaTypes = new ArrayList(allSupportedMediaTypes); - MediaType.sortBySpecificity(this.allSupportedMediaTypes); - } - - /** - * Default conventions, taken from {@link WebMvcConfigurationSupport} with a few minor - * tweaks. - */ - private static class WebMvcConfigurationSupportConventions extends - WebMvcConfigurationSupport { - public List> getDefaultHttpMessageConverters() { - List> converters = new ArrayList>(); - addDefaultHttpMessageConverters(converters); - for (HttpMessageConverter converter : converters) { - if (converter instanceof MappingJackson2HttpMessageConverter) { - MappingJackson2HttpMessageConverter jacksonConverter = (MappingJackson2HttpMessageConverter) converter; - jacksonConverter.getObjectMapper().disable( - SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); - } - } - return converters; - } - } -} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java index 9e65bfa9662..5263e36a3c6 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java @@ -16,33 +16,46 @@ package org.springframework.boot.actuate.endpoint.mvc; +import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.List; - -import javax.servlet.http.HttpServletRequest; +import java.util.Set; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.InitializingBean; import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; -import org.springframework.http.HttpMethod; +import org.springframework.core.annotation.AnnotationUtils; import org.springframework.util.Assert; import org.springframework.util.StringUtils; -import org.springframework.web.servlet.HandlerExecutionChain; import org.springframework.web.servlet.HandlerMapping; -import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping; +import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition; +import org.springframework.web.servlet.mvc.method.RequestMappingInfo; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; /** * {@link HandlerMapping} to map {@link Endpoint}s to URLs via {@link Endpoint#getPath()}. + * Only endpoints that are annotated as @FrameworkEndpoint will be mapped, + * and within that class only those methods with @RequestMapping will be + * exposed. The semantics of @RequestMapping should be identical to a normal + * @Controller, but the endpoints should not be annotated as + * @Controller (otherwise they will be mapped by the normal MVC mechanisms). + * + *

+ * One of the aims of the mapping is to support endpoints that work as HTTP endpoints but + * can still provide useful service interfaces when there is no HTTP server (and no Spring + * MVC on the classpath). Note that any endpoints having method signaturess will break in + * a non-servlet environment. + *

* * @author Phillip Webb * @author Christian Dupuis - * @see EndpointHandlerAdapter + * @author Dave Syer + * */ -public class EndpointHandlerMapping extends AbstractUrlHandlerMapping implements +public class EndpointHandlerMapping extends RequestMappingHandlerMapping implements InitializingBean, ApplicationContextAware { private List> endpoints; @@ -56,28 +69,16 @@ public class EndpointHandlerMapping extends AbstractUrlHandlerMapping implements * detected from the {@link ApplicationContext}. */ public EndpointHandlerMapping() { - setOrder(HIGHEST_PRECEDENCE); - } - - /** - * Create a new {@link EndpointHandlerMapping} with the specified endpoints. - * @param endpoints the endpoints - */ - public EndpointHandlerMapping(Collection> endpoints) { - Assert.notNull(endpoints, "Endpoints must not be null"); - this.endpoints = new ArrayList>(endpoints); + // By default the static resource handler mapping is LOWEST_PRECEDENCE - 1 + setOrder(LOWEST_PRECEDENCE - 2); } @Override - public void afterPropertiesSet() throws Exception { + public void afterPropertiesSet() { + super.afterPropertiesSet(); if (this.endpoints == null) { this.endpoints = findEndpointBeans(); } - if (!this.disabled) { - for (Endpoint endpoint : this.endpoints) { - registerHandler(this.prefix + endpoint.getPath(), endpoint); - } - } } @SuppressWarnings({ "rawtypes", "unchecked" }) @@ -86,20 +87,60 @@ public class EndpointHandlerMapping extends AbstractUrlHandlerMapping implements getApplicationContext(), Endpoint.class).values()); } + /** + * Detects @FrameworkEndpoint annotations in handler beans. + * + * @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#isHandler(java.lang.Class) + */ @Override - protected Object lookupHandler(String urlPath, HttpServletRequest request) - throws Exception { - Object handler = super.lookupHandler(urlPath, request); - if (handler != null) { - Object endpoint = (handler instanceof HandlerExecutionChain ? ((HandlerExecutionChain) handler) - .getHandler() : handler); - HttpMethod method = HttpMethod.valueOf(request.getMethod()); - if (endpoint instanceof Endpoint - && supportsMethod(((Endpoint) endpoint).methods(), method)) { - return endpoint; + protected boolean isHandler(Class beanType) { + if (this.disabled) { + return false; + } + return AnnotationUtils.findAnnotation(beanType, FrameworkEndpoint.class) != null; + } + + @Override + protected void registerHandlerMethod(Object handler, Method method, + RequestMappingInfo mapping) { + + if (mapping == null) { + return; + } + + Set defaultPatterns = mapping.getPatternsCondition().getPatterns(); + String[] patterns = new String[defaultPatterns.isEmpty() ? 1 : defaultPatterns + .size()]; + + String path = ""; + Object bean = handler; + if (bean instanceof String) { + bean = getApplicationContext().getBean((String) handler); + } + if (bean instanceof Endpoint) { + Endpoint endpoint = (Endpoint) bean; + path = endpoint.getPath(); + } + + int i = 0; + String prefix = StringUtils.hasText(this.prefix) ? this.prefix + path : path; + if (defaultPatterns.isEmpty()) { + patterns[0] = prefix; + } + else { + for (String pattern : defaultPatterns) { + patterns[i] = prefix + pattern; + i++; } } - return null; + PatternsRequestCondition patternsInfo = new PatternsRequestCondition(patterns); + + RequestMappingInfo modified = new RequestMappingInfo(patternsInfo, + mapping.getMethodsCondition(), mapping.getParamsCondition(), + mapping.getHeadersCondition(), mapping.getConsumesCondition(), + mapping.getProducesCondition(), mapping.getCustomCondition()); + + super.registerHandlerMethod(handler, method, modified); } /** @@ -131,16 +172,4 @@ public class EndpointHandlerMapping extends AbstractUrlHandlerMapping implements public List> getEndpoints() { return Collections.unmodifiableList(this.endpoints); } - - private boolean supportsMethod(HttpMethod[] supportedMethods, - HttpMethod requestedMethod) { - Assert.notNull(supportedMethods, "SupportMethods must not be null"); - Assert.notNull(supportedMethods, "RequestedMethod must not be null"); - for (HttpMethod supportedMethod : supportedMethods) { - if (supportedMethod.equals(requestedMethod)) { - return true; - } - } - return false; - } } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/FrameworkEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/FrameworkEndpoint.java new file mode 100644 index 00000000000..f1a37e72770 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/FrameworkEndpoint.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012-2013 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.endpoint.mvc; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.stereotype.Component; + +/** + * @author Dave Syer + */ +@Component +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface FrameworkEndpoint { + +} \ No newline at end of file diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/BasicErrorController.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/BasicErrorController.java index 151a20ce2d9..5067aaaacca 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/BasicErrorController.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/BasicErrorController.java @@ -63,7 +63,7 @@ public class BasicErrorController implements ErrorController { @RequestMapping(value = "${error.path:/error}", produces = "text/html") public ModelAndView errorHtml(HttpServletRequest request) { - Map map = extract(new ServletRequestAttributes(request), false); + Map map = error(request); return new ModelAndView(ERROR_KEY, map); } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java index 76b70affe14..521a4f587d3 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java @@ -25,7 +25,7 @@ import org.junit.After; import org.junit.Test; import org.springframework.boot.TestUtils; import org.springframework.boot.actuate.endpoint.AbstractEndpoint; -import org.springframework.boot.actuate.endpoint.Endpoint; +import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; import org.springframework.boot.actuate.properties.ManagementServerProperties; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration; @@ -200,13 +200,8 @@ public class EndpointWebMvcAutoConfigurationTests { } @Bean - public Endpoint testEndpoint() { - return new AbstractEndpoint("/endpoint", false, true) { - @Override - public String doInvoke() { - return "endpointoutput"; - } - }; + public TestEndpoint testEndpoint() { + return new TestEndpoint(); } } @@ -245,4 +240,20 @@ public class EndpointWebMvcAutoConfigurationTests { } + @FrameworkEndpoint + public static class TestEndpoint extends AbstractEndpoint { + + public TestEndpoint() { + super("/endpoint", false, true); + } + + @Override + @RequestMapping + @ResponseBody + public String invoke() { + return "endpointoutput"; + } + + } + } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AbstractEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AbstractEndpointTests.java index 46abfb8ba64..f9f6fb982f1 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AbstractEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AbstractEndpointTests.java @@ -25,7 +25,6 @@ import org.springframework.boot.TestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.PropertySource; -import org.springframework.http.MediaType; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; @@ -49,16 +48,13 @@ public abstract class AbstractEndpointTests> { private final String property; - private MediaType[] produces; - public AbstractEndpointTests(Class configClass, Class type, String path, - boolean sensitive, String property, MediaType... produces) { + boolean sensitive, String property) { this.configClass = configClass; this.type = type; this.path = path; this.sensitive = sensitive; this.property = property; - this.produces = produces; } @Before @@ -75,11 +71,6 @@ public abstract class AbstractEndpointTests> { } } - @Test - public void producesMediaType() { - assertThat(getEndpointBean().produces(), equalTo(this.produces)); - } - @Test public void getPath() throws Exception { assertThat(getEndpointBean().getPath(), equalTo(this.path)); diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/BeansEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/BeansEndpointTests.java index 04804d171d3..ac35cbd3cff 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/BeansEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/BeansEndpointTests.java @@ -17,11 +17,9 @@ package org.springframework.boot.actuate.endpoint; import org.junit.Test; -import org.springframework.boot.actuate.endpoint.BeansEndpoint; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.MediaType; import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertThat; @@ -34,8 +32,7 @@ import static org.junit.Assert.assertThat; public class BeansEndpointTests extends AbstractEndpointTests { public BeansEndpointTests() { - super(Config.class, BeansEndpoint.class, "/beans", true, "endpoints.beans", - MediaType.APPLICATION_JSON); + super(Config.class, BeansEndpoint.class, "/beans", true, "endpoints.beans"); } @Test diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerAdapterTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerAdapterTests.java deleted file mode 100644 index 5877f63a7d6..00000000000 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerAdapterTests.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2012-2013 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.endpoint.mvc; - -import java.util.Collections; -import java.util.Map; - -import org.junit.Test; -import org.springframework.boot.actuate.endpoint.AbstractEndpoint; -import org.springframework.boot.actuate.endpoint.Endpoint; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; - -/** - * Tests for {@link EndpointHandlerAdapter}. - * - * @author Phillip Webb - */ -public class EndpointHandlerAdapterTests { - - private EndpointHandlerAdapter adapter = new EndpointHandlerAdapter(); - private MockHttpServletRequest request = new MockHttpServletRequest(); - private MockHttpServletResponse response = new MockHttpServletResponse(); - - @Test - public void onlySupportsEndpoints() throws Exception { - assertTrue(this.adapter.supports(mock(Endpoint.class))); - assertFalse(this.adapter.supports(mock(Object.class))); - } - - @Test - public void rendersJson() throws Exception { - this.adapter.handle(this.request, this.response, - new AbstractEndpoint>("/foo") { - @Override - protected Map doInvoke() { - return Collections.singletonMap("hello", "world"); - } - }); - assertEquals("{\"hello\":\"world\"}", this.response.getContentAsString()); - } - - @Test - public void rendersString() throws Exception { - this.request.addHeader("Accept", "text/plain"); - this.adapter.handle(this.request, this.response, new AbstractEndpoint( - "/foo") { - @Override - protected String doInvoke() { - return "hello world"; - } - }); - assertEquals("hello world", this.response.getContentAsString()); - } -} diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMappingTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMappingTests.java index 05311da42fb..f18afa22281 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMappingTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMappingTests.java @@ -16,12 +16,18 @@ package org.springframework.boot.actuate.endpoint.mvc; -import java.util.Arrays; +import java.lang.reflect.Method; +import org.junit.Before; import org.junit.Test; import org.springframework.boot.actuate.endpoint.AbstractEndpoint; -import org.springframework.http.HttpMethod; +import org.springframework.context.support.StaticApplicationContext; import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.util.ReflectionUtils; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.method.HandlerMethod; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.nullValue; @@ -33,21 +39,38 @@ import static org.junit.Assert.assertThat; * Tests for {@link EndpointHandlerMapping}. * * @author Phillip Webb + * @author Dave Syer */ public class EndpointHandlerMappingTests { + private StaticApplicationContext context = new StaticApplicationContext(); + private EndpointHandlerMapping mapping = new EndpointHandlerMapping(); + private Method method; + + @Before + public void init() throws Exception { + this.context.getDefaultListableBeanFactory().registerSingleton("mapping", + this.mapping); + this.mapping.setApplicationContext(this.context); + this.method = ReflectionUtils.findMethod(TestEndpoint.class, "invoke"); + } + @Test public void withoutPrefix() throws Exception { TestEndpoint endpointA = new TestEndpoint("/a"); TestEndpoint endpointB = new TestEndpoint("/b"); - EndpointHandlerMapping mapping = new EndpointHandlerMapping(Arrays.asList( - endpointA, endpointB)); - mapping.afterPropertiesSet(); - assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/a")) - .getHandler(), equalTo((Object) endpointA)); - assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/b")) - .getHandler(), equalTo((Object) endpointB)); - assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/c")), + this.context.getDefaultListableBeanFactory().registerSingleton( + endpointA.getPath(), endpointA); + this.context.getDefaultListableBeanFactory().registerSingleton( + endpointB.getPath(), endpointB); + this.mapping.afterPropertiesSet(); + assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a")) + .getHandler(), + equalTo((Object) new HandlerMethod(endpointA, this.method))); + assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/b")) + .getHandler(), + equalTo((Object) new HandlerMethod(endpointB, this.method))); + assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/c")), nullValue()); } @@ -55,49 +78,63 @@ public class EndpointHandlerMappingTests { public void withPrefix() throws Exception { TestEndpoint endpointA = new TestEndpoint("/a"); TestEndpoint endpointB = new TestEndpoint("/b"); - EndpointHandlerMapping mapping = new EndpointHandlerMapping(Arrays.asList( - endpointA, endpointB)); - mapping.setPrefix("/a"); - mapping.afterPropertiesSet(); - assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/a/a")) - .getHandler(), equalTo((Object) endpointA)); - assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/a/b")) - .getHandler(), equalTo((Object) endpointB)); - assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/a")), + this.context.getDefaultListableBeanFactory().registerSingleton( + endpointA.getPath(), endpointA); + this.context.getDefaultListableBeanFactory().registerSingleton( + endpointB.getPath(), endpointB); + this.mapping.setPrefix("/a"); + this.mapping.afterPropertiesSet(); + assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a/a")) + .getHandler(), + equalTo((Object) new HandlerMethod(endpointA, this.method))); + assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a/b")) + .getHandler(), + equalTo((Object) new HandlerMethod(endpointB, this.method))); + assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a")), nullValue()); } - @Test + @Test(expected = HttpRequestMethodNotSupportedException.class) public void onlyGetHttpMethodForNonActionEndpoints() throws Exception { TestEndpoint endpoint = new TestEndpoint("/a"); - EndpointHandlerMapping mapping = new EndpointHandlerMapping( - Arrays.asList(endpoint)); - mapping.afterPropertiesSet(); - assertNotNull(mapping.getHandler(new MockHttpServletRequest("GET", "/a"))); - assertNull(mapping.getHandler(new MockHttpServletRequest("POST", "/a"))); + this.context.getDefaultListableBeanFactory().registerSingleton( + endpoint.getPath(), endpoint); + this.mapping.afterPropertiesSet(); + assertNotNull(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a"))); + assertNull(this.mapping.getHandler(new MockHttpServletRequest("POST", "/a"))); } @Test + public void postHttpMethodForActionEndpoints() throws Exception { + TestEndpoint endpoint = new TestActionEndpoint("/a"); + this.context.getDefaultListableBeanFactory().registerSingleton( + endpoint.getPath(), endpoint); + this.mapping.afterPropertiesSet(); + assertNotNull(this.mapping.getHandler(new MockHttpServletRequest("POST", "/a"))); + } + + @Test(expected = HttpRequestMethodNotSupportedException.class) public void onlyPostHttpMethodForActionEndpoints() throws Exception { TestEndpoint endpoint = new TestActionEndpoint("/a"); - EndpointHandlerMapping mapping = new EndpointHandlerMapping( - Arrays.asList(endpoint)); - mapping.afterPropertiesSet(); - assertNull(mapping.getHandler(new MockHttpServletRequest("GET", "/a"))); - assertNotNull(mapping.getHandler(new MockHttpServletRequest("POST", "/a"))); + this.context.getDefaultListableBeanFactory().registerSingleton( + endpoint.getPath(), endpoint); + this.mapping.afterPropertiesSet(); + assertNotNull(this.mapping.getHandler(new MockHttpServletRequest("POST", "/a"))); + assertNull(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a"))); } @Test public void disabled() throws Exception { - TestEndpoint endpointA = new TestEndpoint("/a"); - EndpointHandlerMapping mapping = new EndpointHandlerMapping( - Arrays.asList(endpointA)); - mapping.setDisabled(true); - mapping.afterPropertiesSet(); - assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/a")), + TestEndpoint endpoint = new TestEndpoint("/a"); + this.context.getDefaultListableBeanFactory().registerSingleton( + endpoint.getPath(), endpoint); + this.mapping.setDisabled(true); + this.mapping.afterPropertiesSet(); + assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a")), nullValue()); } + @FrameworkEndpoint private static class TestEndpoint extends AbstractEndpoint { public TestEndpoint(String path) { @@ -105,12 +142,14 @@ public class EndpointHandlerMappingTests { } @Override - public Object doInvoke() { + @RequestMapping(method = RequestMethod.GET) + public Object invoke() { return null; } } + @FrameworkEndpoint private static class TestActionEndpoint extends TestEndpoint { public TestActionEndpoint(String path) { @@ -118,8 +157,9 @@ public class EndpointHandlerMappingTests { } @Override - public HttpMethod[] methods() { - return POST_HTTP_METHOD; + @RequestMapping(method = RequestMethod.POST) + public Object invoke() { + return null; } } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/BasicErrorControllerIntegrationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/BasicErrorControllerIntegrationTests.java index 7dbfefdf892..d23b10a670c 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/BasicErrorControllerIntegrationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/BasicErrorControllerIntegrationTests.java @@ -26,8 +26,10 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; +import org.springframework.boot.actuate.autoconfigure.ManagementSecurityAutoConfiguration; import org.springframework.boot.actuate.web.BasicErrorControllerIntegrationTests.TestConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -81,7 +83,8 @@ public class BasicErrorControllerIntegrationTests { } @Configuration - @EnableAutoConfiguration + @EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class, + ManagementSecurityAutoConfiguration.class }) public static class TestConfiguration { // For manual testing diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/BasicErrorControllerSpecialIntegrationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/BasicErrorControllerSpecialIntegrationTests.java index 7cabdf463d6..efbc69ff7f4 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/BasicErrorControllerSpecialIntegrationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/BasicErrorControllerSpecialIntegrationTests.java @@ -19,7 +19,9 @@ package org.springframework.boot.actuate.web; import org.junit.After; import org.junit.Test; import org.springframework.boot.SpringApplication; +import org.springframework.boot.actuate.autoconfigure.ManagementSecurityAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; @@ -77,13 +79,15 @@ public class BasicErrorControllerSpecialIntegrationTests { } @Configuration - @EnableAutoConfiguration + @EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class, + ManagementSecurityAutoConfiguration.class }) protected static class ParentConfiguration { } @Configuration - @EnableAutoConfiguration + @EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class, + ManagementSecurityAutoConfiguration.class }) @EnableWebMvc protected static class WebMvcIncludedConfiguration { // For manual testing @@ -94,7 +98,19 @@ public class BasicErrorControllerSpecialIntegrationTests { } @Configuration - @EnableAutoConfiguration + @EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class, + ManagementSecurityAutoConfiguration.class }) + protected static class VanillaConfiguration { + // For manual testing + public static void main(String[] args) { + SpringApplication.run(VanillaConfiguration.class, args); + } + + } + + @Configuration + @EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class, + ManagementSecurityAutoConfiguration.class }) protected static class ChildConfiguration { // For manual testing From 332f23a0eeb7d699e860f5fd445ae7f8fd621121 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 9 Dec 2013 12:00:36 +0000 Subject: [PATCH 02/10] Add parent properties to config props endpoint --- ...ConfigurationPropertiesReportEndpoint.java | 20 +++- ...onPropertiesReportEndpointParentTests.java | 103 ++++++++++++++++++ ...gurationPropertiesReportEndpointTests.java | 48 ++++---- 3 files changed, 147 insertions(+), 24 deletions(-) create mode 100644 spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointParentTests.java diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java index fca2a4eea4c..95fa306e7c6 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java @@ -34,8 +34,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; * annotated classes. * *

- * To protect sensitive information from being exposed, configure property names by using - * endpoints.configprops.keys_to_sanitize. + * To protect sensitive information from being exposed, certain property values are masked + * if their names end with a set of configurable values (default "password" and "secret"). + * Configure property names by using {@link #setKeysToSanitize(String[])}. * * @author Christian Dupuis */ @@ -66,12 +67,17 @@ public class ConfigurationPropertiesReportEndpoint extends this.keysToSanitize = keysToSanitize; } - @Override - @SuppressWarnings("unchecked") @RequestMapping @ResponseBody public Map invoke() { - Map beans = this.context + Map beans = extract(this.context); + return beans; + } + + @SuppressWarnings("unchecked") + private Map extract(ApplicationContext context) { + + Map beans = context .getBeansWithAnnotation(ConfigurationProperties.class); // Serialize beans into map structure and sanitize values @@ -81,6 +87,10 @@ public class ConfigurationPropertiesReportEndpoint extends beans.put(entry.getKey(), sanitize(value)); } + if (context.getParent() != null) { + beans.put("parent", extract(context.getParent())); + } + return beans; } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointParentTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointParentTests.java new file mode 100644 index 00000000000..e45923e9677 --- /dev/null +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointParentTests.java @@ -0,0 +1,103 @@ +/* + * Copyright 2013 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.endpoint; + +import java.util.Map; + +import org.junit.After; +import org.junit.Test; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class ConfigurationPropertiesReportEndpointParentTests { + + private AnnotationConfigApplicationContext context; + + @After + public void close() { + if (this.context != null) { + this.context.close(); + if (this.context.getParent() != null) { + ((ConfigurableApplicationContext) this.context.getParent()).close(); + } + } + } + + @Test + public void testInvoke() throws Exception { + AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext(); + parent.register(Parent.class); + parent.refresh(); + this.context = new AnnotationConfigApplicationContext(); + this.context.setParent(parent); + this.context.register(Config.class); + this.context.refresh(); + ConfigurationPropertiesReportEndpoint endpoint = this.context + .getBean(ConfigurationPropertiesReportEndpoint.class); + Map result = endpoint.invoke(); + assertTrue(result.containsKey("parent")); + assertEquals(3, result.size()); // the endpoint, the test props and the parent + // System.err.println(result); + } + + @Configuration + @EnableConfigurationProperties + public static class Parent { + @Bean + public TestProperties testProperties() { + return new TestProperties(); + } + } + + @Configuration + @EnableConfigurationProperties + public static class Config { + + @Bean + public ConfigurationPropertiesReportEndpoint endpoint() { + return new ConfigurationPropertiesReportEndpoint(); + } + + @Bean + public TestProperties testProperties() { + return new TestProperties(); + } + + } + + @ConfigurationProperties(name = "test") + public static class TestProperties { + + private String myTestProperty = "654321"; + + public String getMyTestProperty() { + return this.myTestProperty; + } + + public void setMyTestProperty(String myTestProperty) { + this.myTestProperty = myTestProperty; + } + + } +} diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointTests.java index 0e7edecb8a4..3fad25b0280 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointTests.java @@ -68,6 +68,15 @@ public class ConfigurationPropertiesReportEndpointTests extends assertEquals("******", nestedProperties.get("myTestProperty")); } + @Configuration + @EnableConfigurationProperties + public static class Parent { + @Bean + public TestProperties testProperties() { + return new TestProperties(); + } + } + @Configuration @EnableConfigurationProperties public static class Config { @@ -82,29 +91,30 @@ public class ConfigurationPropertiesReportEndpointTests extends return new TestProperties(); } - @ConfigurationProperties(name = "test") - public static class TestProperties { + } - private String dbPassword = "123456"; + @ConfigurationProperties(name = "test") + public static class TestProperties { - private String myTestProperty = "654321"; + private String dbPassword = "123456"; - public String getDbPassword() { - return this.dbPassword; - } - - public void setDbPassword(String dbPassword) { - this.dbPassword = dbPassword; - } - - public String getMyTestProperty() { - return this.myTestProperty; - } - - public void setMyTestProperty(String myTestProperty) { - this.myTestProperty = myTestProperty; - } + private String myTestProperty = "654321"; + public String getDbPassword() { + return this.dbPassword; } + + public void setDbPassword(String dbPassword) { + this.dbPassword = dbPassword; + } + + public String getMyTestProperty() { + return this.myTestProperty; + } + + public void setMyTestProperty(String myTestProperty) { + this.myTestProperty = myTestProperty; + } + } } From ab4dec58ef548bbcada17a1da66ad58ccd70a518 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 9 Dec 2013 16:16:59 +0000 Subject: [PATCH 03/10] Rename packages in samples --- .../{ops => actuator}/ui/SampleActuatorUiApplication.java | 2 +- .../ui/SampleActuatorUiApplicationPortTests.java | 3 ++- .../{ops => actuator}/ui/SampleActuatorUiApplicationTests.java | 3 ++- .../boot/sample/{ops => actuator}/HelloWorldService.java | 2 +- .../sample/{ops => actuator}/SampleActuatorApplication.java | 2 +- .../boot/sample/{ops => actuator}/SampleController.java | 2 +- .../boot/sample/{ops => actuator}/ServiceProperties.java | 2 +- .../EndpointsPropertiesSampleActuatorApplicationTests.java | 3 ++- .../ManagementAddressSampleActuatorApplicationTests.java | 3 ++- .../ManagementSampleActuatorApplicationTests.java | 3 ++- .../NoManagementSampleActuatorApplicationTests.java | 3 ++- .../{ops => actuator}/SampleActuatorApplicationTests.java | 3 ++- .../ShutdownSampleActuatorApplicationTests.java | 3 ++- .../UnsecureManagementSampleActuatorApplicationTests.java | 3 ++- .../UnsecureSampleActuatorApplicationTests.java | 3 ++- 15 files changed, 25 insertions(+), 15 deletions(-) rename spring-boot-samples/spring-boot-sample-actuator-ui/src/main/java/org/springframework/boot/sample/{ops => actuator}/ui/SampleActuatorUiApplication.java (97%) rename spring-boot-samples/spring-boot-sample-actuator-ui/src/test/java/org/springframework/boot/sample/{ops => actuator}/ui/SampleActuatorUiApplicationPortTests.java (96%) rename spring-boot-samples/spring-boot-sample-actuator-ui/src/test/java/org/springframework/boot/sample/{ops => actuator}/ui/SampleActuatorUiApplicationTests.java (97%) rename spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/{ops => actuator}/HelloWorldService.java (94%) rename spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/{ops => actuator}/SampleActuatorApplication.java (96%) rename spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/{ops => actuator}/SampleController.java (96%) rename spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/{ops => actuator}/ServiceProperties.java (95%) rename spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/{ops => actuator}/EndpointsPropertiesSampleActuatorApplicationTests.java (97%) rename spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/{ops => actuator}/ManagementAddressSampleActuatorApplicationTests.java (97%) rename spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/{ops => actuator}/ManagementSampleActuatorApplicationTests.java (96%) rename spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/{ops => actuator}/NoManagementSampleActuatorApplicationTests.java (97%) rename spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/{ops => actuator}/SampleActuatorApplicationTests.java (98%) rename spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/{ops => actuator}/ShutdownSampleActuatorApplicationTests.java (97%) rename spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/{ops => actuator}/UnsecureManagementSampleActuatorApplicationTests.java (96%) rename spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/{ops => actuator}/UnsecureSampleActuatorApplicationTests.java (95%) diff --git a/spring-boot-samples/spring-boot-sample-actuator-ui/src/main/java/org/springframework/boot/sample/ops/ui/SampleActuatorUiApplication.java b/spring-boot-samples/spring-boot-sample-actuator-ui/src/main/java/org/springframework/boot/sample/actuator/ui/SampleActuatorUiApplication.java similarity index 97% rename from spring-boot-samples/spring-boot-sample-actuator-ui/src/main/java/org/springframework/boot/sample/ops/ui/SampleActuatorUiApplication.java rename to spring-boot-samples/spring-boot-sample-actuator-ui/src/main/java/org/springframework/boot/sample/actuator/ui/SampleActuatorUiApplication.java index 73d4cfa0946..927a2ba5228 100644 --- a/spring-boot-samples/spring-boot-sample-actuator-ui/src/main/java/org/springframework/boot/sample/ops/ui/SampleActuatorUiApplication.java +++ b/spring-boot-samples/spring-boot-sample-actuator-ui/src/main/java/org/springframework/boot/sample/actuator/ui/SampleActuatorUiApplication.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.sample.ops.ui; +package org.springframework.boot.sample.actuator.ui; import java.util.Date; import java.util.Map; diff --git a/spring-boot-samples/spring-boot-sample-actuator-ui/src/test/java/org/springframework/boot/sample/ops/ui/SampleActuatorUiApplicationPortTests.java b/spring-boot-samples/spring-boot-sample-actuator-ui/src/test/java/org/springframework/boot/sample/actuator/ui/SampleActuatorUiApplicationPortTests.java similarity index 96% rename from spring-boot-samples/spring-boot-sample-actuator-ui/src/test/java/org/springframework/boot/sample/ops/ui/SampleActuatorUiApplicationPortTests.java rename to spring-boot-samples/spring-boot-sample-actuator-ui/src/test/java/org/springframework/boot/sample/actuator/ui/SampleActuatorUiApplicationPortTests.java index 95487b418ae..bf310ced5e9 100644 --- a/spring-boot-samples/spring-boot-sample-actuator-ui/src/test/java/org/springframework/boot/sample/ops/ui/SampleActuatorUiApplicationPortTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator-ui/src/test/java/org/springframework/boot/sample/actuator/ui/SampleActuatorUiApplicationPortTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.sample.ops.ui; +package org.springframework.boot.sample.actuator.ui; import static org.junit.Assert.assertEquals; @@ -29,6 +29,7 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.boot.SpringApplication; +import org.springframework.boot.sample.actuator.ui.SampleActuatorUiApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; diff --git a/spring-boot-samples/spring-boot-sample-actuator-ui/src/test/java/org/springframework/boot/sample/ops/ui/SampleActuatorUiApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator-ui/src/test/java/org/springframework/boot/sample/actuator/ui/SampleActuatorUiApplicationTests.java similarity index 97% rename from spring-boot-samples/spring-boot-sample-actuator-ui/src/test/java/org/springframework/boot/sample/ops/ui/SampleActuatorUiApplicationTests.java rename to spring-boot-samples/spring-boot-sample-actuator-ui/src/test/java/org/springframework/boot/sample/actuator/ui/SampleActuatorUiApplicationTests.java index 8960d3c2591..6d731abbdca 100644 --- a/spring-boot-samples/spring-boot-sample-actuator-ui/src/test/java/org/springframework/boot/sample/ops/ui/SampleActuatorUiApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator-ui/src/test/java/org/springframework/boot/sample/actuator/ui/SampleActuatorUiApplicationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.sample.ops.ui; +package org.springframework.boot.sample.actuator.ui; import java.io.IOException; import java.util.Arrays; @@ -28,6 +28,7 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.boot.SpringApplication; +import org.springframework.boot.sample.actuator.ui.SampleActuatorUiApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/ops/HelloWorldService.java b/spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/actuator/HelloWorldService.java similarity index 94% rename from spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/ops/HelloWorldService.java rename to spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/actuator/HelloWorldService.java index 342c02a8850..baea40d432f 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/ops/HelloWorldService.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/actuator/HelloWorldService.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.sample.ops; +package org.springframework.boot.sample.actuator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/ops/SampleActuatorApplication.java b/spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/actuator/SampleActuatorApplication.java similarity index 96% rename from spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/ops/SampleActuatorApplication.java rename to spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/actuator/SampleActuatorApplication.java index 1e747a7f9ce..c7e73fff1c3 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/ops/SampleActuatorApplication.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/actuator/SampleActuatorApplication.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.sample.ops; +package org.springframework.boot.sample.actuator; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/ops/SampleController.java b/spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/actuator/SampleController.java similarity index 96% rename from spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/ops/SampleController.java rename to spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/actuator/SampleController.java index 4c5f9950e25..ffb6a0c083d 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/ops/SampleController.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/actuator/SampleController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.sample.ops; +package org.springframework.boot.sample.actuator; import java.util.Collections; import java.util.Map; diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/ops/ServiceProperties.java b/spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/actuator/ServiceProperties.java similarity index 95% rename from spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/ops/ServiceProperties.java rename to spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/actuator/ServiceProperties.java index 83a119b8651..5b111e166ec 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/ops/ServiceProperties.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/main/java/org/springframework/boot/sample/actuator/ServiceProperties.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.sample.ops; +package org.springframework.boot.sample.actuator; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/EndpointsPropertiesSampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/EndpointsPropertiesSampleActuatorApplicationTests.java similarity index 97% rename from spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/EndpointsPropertiesSampleActuatorApplicationTests.java rename to spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/EndpointsPropertiesSampleActuatorApplicationTests.java index 5dad069baa8..b4991a7fe1d 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/EndpointsPropertiesSampleActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/EndpointsPropertiesSampleActuatorApplicationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.sample.ops; +package org.springframework.boot.sample.actuator; import java.io.IOException; import java.util.ArrayList; @@ -28,6 +28,7 @@ import java.util.concurrent.TimeUnit; import org.junit.After; import org.junit.Test; import org.springframework.boot.SpringApplication; +import org.springframework.boot.sample.actuator.SampleActuatorApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.http.HttpRequest; import org.springframework.http.HttpStatus; diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/ManagementAddressSampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/ManagementAddressSampleActuatorApplicationTests.java similarity index 97% rename from spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/ManagementAddressSampleActuatorApplicationTests.java rename to spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/ManagementAddressSampleActuatorApplicationTests.java index 7456e49fc9f..b5019067469 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/ManagementAddressSampleActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/ManagementAddressSampleActuatorApplicationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.sample.ops; +package org.springframework.boot.sample.actuator; import static org.junit.Assert.assertEquals; @@ -32,6 +32,7 @@ import org.junit.BeforeClass; import org.junit.Test; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.security.SecurityProperties; +import org.springframework.boot.sample.actuator.SampleActuatorApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.http.HttpRequest; import org.springframework.http.HttpStatus; diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/ManagementSampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/ManagementSampleActuatorApplicationTests.java similarity index 96% rename from spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/ManagementSampleActuatorApplicationTests.java rename to spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/ManagementSampleActuatorApplicationTests.java index e54fef2beeb..561b65d3171 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/ManagementSampleActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/ManagementSampleActuatorApplicationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.sample.ops; +package org.springframework.boot.sample.actuator; import java.io.IOException; import java.util.Map; @@ -27,6 +27,7 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.boot.SpringApplication; +import org.springframework.boot.sample.actuator.SampleActuatorApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/NoManagementSampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/NoManagementSampleActuatorApplicationTests.java similarity index 97% rename from spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/NoManagementSampleActuatorApplicationTests.java rename to spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/NoManagementSampleActuatorApplicationTests.java index 311b82005c1..3e11caf2c72 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/NoManagementSampleActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/NoManagementSampleActuatorApplicationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.sample.ops; +package org.springframework.boot.sample.actuator; import java.io.IOException; import java.util.ArrayList; @@ -30,6 +30,7 @@ import org.junit.BeforeClass; import org.junit.Test; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.security.SecurityProperties; +import org.springframework.boot.sample.actuator.SampleActuatorApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.http.HttpRequest; import org.springframework.http.HttpStatus; diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/SampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/SampleActuatorApplicationTests.java similarity index 98% rename from spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/SampleActuatorApplicationTests.java rename to spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/SampleActuatorApplicationTests.java index b5fffe09a48..28762898536 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/SampleActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/SampleActuatorApplicationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.sample.ops; +package org.springframework.boot.sample.actuator; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -36,6 +36,7 @@ import org.junit.BeforeClass; import org.junit.Test; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.security.SecurityProperties; +import org.springframework.boot.sample.actuator.SampleActuatorApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/ShutdownSampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/ShutdownSampleActuatorApplicationTests.java similarity index 97% rename from spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/ShutdownSampleActuatorApplicationTests.java rename to spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/ShutdownSampleActuatorApplicationTests.java index aa4bc9b0c7d..3d7f35471cc 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/ShutdownSampleActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/ShutdownSampleActuatorApplicationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.sample.ops; +package org.springframework.boot.sample.actuator; import java.io.IOException; import java.util.ArrayList; @@ -30,6 +30,7 @@ import org.junit.BeforeClass; import org.junit.Test; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.security.SecurityProperties; +import org.springframework.boot.sample.actuator.SampleActuatorApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.http.HttpRequest; import org.springframework.http.HttpStatus; diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/UnsecureManagementSampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/UnsecureManagementSampleActuatorApplicationTests.java similarity index 96% rename from spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/UnsecureManagementSampleActuatorApplicationTests.java rename to spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/UnsecureManagementSampleActuatorApplicationTests.java index 48a17a4e886..dc619da376b 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/UnsecureManagementSampleActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/UnsecureManagementSampleActuatorApplicationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.sample.ops; +package org.springframework.boot.sample.actuator; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -31,6 +31,7 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.boot.SpringApplication; +import org.springframework.boot.sample.actuator.SampleActuatorApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/UnsecureSampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/UnsecureSampleActuatorApplicationTests.java similarity index 95% rename from spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/UnsecureSampleActuatorApplicationTests.java rename to spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/UnsecureSampleActuatorApplicationTests.java index 9a2516cfd85..bac04e3fce5 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/ops/UnsecureSampleActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/org/springframework/boot/sample/actuator/UnsecureSampleActuatorApplicationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.sample.ops; +package org.springframework.boot.sample.actuator; import java.io.IOException; import java.util.Map; @@ -27,6 +27,7 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.boot.SpringApplication; +import org.springframework.boot.sample.actuator.SampleActuatorApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; From 6443800038665209ab0760497118f0f902408d25 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 9 Dec 2013 16:17:53 +0000 Subject: [PATCH 04/10] Add actuator-noweb sample --- .../EndpointAutoConfiguration.java | 3 - spring-boot-samples/pom.xml | 1 + .../spring-boot-sample-actuator-noweb/pom.xml | 34 ++++++++++ .../sample/actuator/HelloWorldService.java | 32 +++++++++ .../SampleActuatorNoWebApplication.java | 35 ++++++++++ .../sample/actuator/ServiceProperties.java | 36 ++++++++++ .../src/main/resources/application.properties | 5 ++ .../SampleActuatorNoWebApplicationTests.java | 68 +++++++++++++++++++ 8 files changed, 211 insertions(+), 3 deletions(-) create mode 100644 spring-boot-samples/spring-boot-sample-actuator-noweb/pom.xml create mode 100644 spring-boot-samples/spring-boot-sample-actuator-noweb/src/main/java/org/springframework/boot/sample/actuator/HelloWorldService.java create mode 100644 spring-boot-samples/spring-boot-sample-actuator-noweb/src/main/java/org/springframework/boot/sample/actuator/SampleActuatorNoWebApplication.java create mode 100644 spring-boot-samples/spring-boot-sample-actuator-noweb/src/main/java/org/springframework/boot/sample/actuator/ServiceProperties.java create mode 100644 spring-boot-samples/spring-boot-sample-actuator-noweb/src/main/resources/application.properties create mode 100644 spring-boot-samples/spring-boot-sample-actuator-noweb/src/test/java/org/springframework/boot/sample/actuator/SampleActuatorNoWebApplicationTests.java diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java index 5cf1e88c7ef..3033494544d 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java @@ -47,7 +47,6 @@ import org.springframework.boot.actuate.trace.TraceRepository; import org.springframework.boot.autoconfigure.AutoConfigurationReport; 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.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.SearchStrategy; import org.springframework.boot.bind.PropertiesConfigurationFactory; @@ -57,7 +56,6 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.StandardEnvironment; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PropertiesLoaderUtils; -import org.springframework.http.MediaType; /** * {@link EnableAutoConfiguration Auto-configuration} for common management @@ -68,7 +66,6 @@ import org.springframework.http.MediaType; * @author Greg Turnquist */ @Configuration -@ConditionalOnClass(MediaType.class) public class EndpointAutoConfiguration { @Autowired(required = false) diff --git a/spring-boot-samples/pom.xml b/spring-boot-samples/pom.xml index 752fe1ab226..0ee8f5348ce 100644 --- a/spring-boot-samples/pom.xml +++ b/spring-boot-samples/pom.xml @@ -16,6 +16,7 @@ spring-boot-sample-actuator spring-boot-sample-actuator-log4j + spring-boot-sample-actuator-noweb spring-boot-sample-actuator-ui spring-boot-sample-amqp spring-boot-sample-aop diff --git a/spring-boot-samples/spring-boot-sample-actuator-noweb/pom.xml b/spring-boot-samples/spring-boot-sample-actuator-noweb/pom.xml new file mode 100644 index 00000000000..de4eef79d0a --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-actuator-noweb/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-samples + 0.5.0.BUILD-SNAPSHOT + + spring-boot-sample-actuator-noweb + jar + + ${basedir}/../.. + + + + ${project.groupId} + spring-boot-starter-actuator + + + ${project.groupId} + spring-boot-starter-shell-remote + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/spring-boot-samples/spring-boot-sample-actuator-noweb/src/main/java/org/springframework/boot/sample/actuator/HelloWorldService.java b/spring-boot-samples/spring-boot-sample-actuator-noweb/src/main/java/org/springframework/boot/sample/actuator/HelloWorldService.java new file mode 100644 index 00000000000..baea40d432f --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-actuator-noweb/src/main/java/org/springframework/boot/sample/actuator/HelloWorldService.java @@ -0,0 +1,32 @@ +/* + * Copyright 2012-2013 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.sample.actuator; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class HelloWorldService { + + @Autowired + private ServiceProperties configuration; + + public String getHelloMessage() { + return "Hello " + this.configuration.getName(); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-actuator-noweb/src/main/java/org/springframework/boot/sample/actuator/SampleActuatorNoWebApplication.java b/spring-boot-samples/spring-boot-sample-actuator-noweb/src/main/java/org/springframework/boot/sample/actuator/SampleActuatorNoWebApplication.java new file mode 100644 index 00000000000..eee9972708e --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-actuator-noweb/src/main/java/org/springframework/boot/sample/actuator/SampleActuatorNoWebApplication.java @@ -0,0 +1,35 @@ +/* + * Copyright 2012-2013 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.sample.actuator; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableAutoConfiguration +@EnableConfigurationProperties +@ComponentScan +public class SampleActuatorNoWebApplication { + + public static void main(String[] args) throws Exception { + SpringApplication.run(SampleActuatorNoWebApplication.class, args); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-actuator-noweb/src/main/java/org/springframework/boot/sample/actuator/ServiceProperties.java b/spring-boot-samples/spring-boot-sample-actuator-noweb/src/main/java/org/springframework/boot/sample/actuator/ServiceProperties.java new file mode 100644 index 00000000000..5b111e166ec --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-actuator-noweb/src/main/java/org/springframework/boot/sample/actuator/ServiceProperties.java @@ -0,0 +1,36 @@ +/* + * Copyright 2012-2013 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.sample.actuator; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@ConfigurationProperties(name = "service", ignoreUnknownFields = false) +@Component +public class ServiceProperties { + + private String name = "World"; + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/spring-boot-samples/spring-boot-sample-actuator-noweb/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-actuator-noweb/src/main/resources/application.properties new file mode 100644 index 00000000000..3df2e92ef3b --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-actuator-noweb/src/main/resources/application.properties @@ -0,0 +1,5 @@ +service.name: Phil +shell.ssh.enabled: true +shell.ssh.port: 2222 +shell.auth: simple +shell.auth.simple.user.password: password diff --git a/spring-boot-samples/spring-boot-sample-actuator-noweb/src/test/java/org/springframework/boot/sample/actuator/SampleActuatorNoWebApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator-noweb/src/test/java/org/springframework/boot/sample/actuator/SampleActuatorNoWebApplicationTests.java new file mode 100644 index 00000000000..8711f8a4563 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-actuator-noweb/src/test/java/org/springframework/boot/sample/actuator/SampleActuatorNoWebApplicationTests.java @@ -0,0 +1,68 @@ +/* + * Copyright 2012-2013 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.sample.actuator; + +import static org.junit.Assert.assertNotNull; + +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.actuate.endpoint.MetricsEndpoint; +import org.springframework.context.ConfigurableApplicationContext; + +/** + * Basic integration tests for service demo application. + * + * @author Dave Syer + */ +public class SampleActuatorNoWebApplicationTests { + + private static ConfigurableApplicationContext context; + + @BeforeClass + public static void start() throws Exception { + Future future = Executors + .newSingleThreadExecutor().submit( + new Callable() { + @Override + public ConfigurableApplicationContext call() throws Exception { + return SpringApplication + .run(SampleActuatorNoWebApplication.class); + } + }); + context = future.get(60, TimeUnit.SECONDS); + } + + @AfterClass + public static void stop() { + if (context != null) { + context.close(); + } + } + + @Test + public void endpointsExist() throws Exception { + assertNotNull(context.getBean(MetricsEndpoint.class)); + } + +} From 71ebcbff3ef2936c20130aa8ee36e3f16ed78824 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 9 Dec 2013 16:19:19 +0000 Subject: [PATCH 05/10] Add beans and autoconfig reports to shell --- .../commands/crash/autoconfig.groovy | 29 +++++++++++++++++++ .../resources/commands/crash/beans.groovy | 17 +++++++++++ 2 files changed, 46 insertions(+) create mode 100644 spring-boot-starters/spring-boot-starter-shell-remote/src/main/resources/commands/crash/autoconfig.groovy create mode 100644 spring-boot-starters/spring-boot-starter-shell-remote/src/main/resources/commands/crash/beans.groovy diff --git a/spring-boot-starters/spring-boot-starter-shell-remote/src/main/resources/commands/crash/autoconfig.groovy b/spring-boot-starters/spring-boot-starter-shell-remote/src/main/resources/commands/crash/autoconfig.groovy new file mode 100644 index 00000000000..3f4dc27beef --- /dev/null +++ b/spring-boot-starters/spring-boot-starter-shell-remote/src/main/resources/commands/crash/autoconfig.groovy @@ -0,0 +1,29 @@ +package commands + +import org.springframework.boot.actuate.endpoint.AutoConfigurationReportEndpoint + +class autoconfig { + + @Usage("Display auto configuration report from ApplicationContext") + @Command + void main(InvocationContext context) { + context.attributes['spring.beanfactory'].getBeansOfType(AutoConfigurationReportEndpoint.class).each { name, endpoint -> + def report = endpoint.invoke() + out.println "Endpoint: " + name + "\n\nPositive Matches:\n================\n" + report.positiveMatches.each { key, list -> + out.println key + ":" + list.each { mandc -> + out.println " " + mandc.condition + ": " + mandc.message + } + } + out.println "\nNegative Matches\n================\n" + report.negativeMatches.each { key, list -> + out.println key + ":" + list.each { mandc -> + out.println " " + mandc.condition + ": " + mandc.message + } + } + } + } + +} \ No newline at end of file diff --git a/spring-boot-starters/spring-boot-starter-shell-remote/src/main/resources/commands/crash/beans.groovy b/spring-boot-starters/spring-boot-starter-shell-remote/src/main/resources/commands/crash/beans.groovy new file mode 100644 index 00000000000..67fea1cada5 --- /dev/null +++ b/spring-boot-starters/spring-boot-starter-shell-remote/src/main/resources/commands/crash/beans.groovy @@ -0,0 +1,17 @@ +package commands + +import org.springframework.boot.actuate.endpoint.BeansEndpoint + +class beans { + + @Usage("Display beans in ApplicationContext") + @Command + def main(InvocationContext context) { + def result = [:] + context.attributes['spring.beanfactory'].getBeansOfType(BeansEndpoint.class).each { name, endpoint -> + result.put(name, endpoint.invoke()) + } + result.size() == 1 ? result.values()[0] : result + } + +} \ No newline at end of file From 87e00cfae9ab237e37df3f67e97eaa56957c857e Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Wed, 18 Dec 2013 11:04:32 +0000 Subject: [PATCH 06/10] Extract MVC concerns completely from Endpoint implementations --- .../EndpointWebMvcAutoConfiguration.java | 58 +++++++++++++++++ .../boot/actuate/endpoint/BeansEndpoint.java | 19 +++--- ...ConfigurationPropertiesReportEndpoint.java | 7 +- .../boot/actuate/endpoint/DumpEndpoint.java | 6 -- .../actuate/endpoint/EnvironmentEndpoint.java | 30 +-------- .../boot/actuate/endpoint/HealthEndpoint.java | 6 -- .../boot/actuate/endpoint/InfoEndpoint.java | 6 -- .../endpoint/ManagementErrorEndpoint.java | 14 ++-- .../actuate/endpoint/MetricsEndpoint.java | 27 -------- .../actuate/endpoint/ShutdownEndpoint.java | 40 ++++++------ .../boot/actuate/endpoint/TraceEndpoint.java | 6 -- .../endpoint/mvc/EndpointHandlerMapping.java | 4 +- .../endpoint/mvc/EnvironmentMvcEndpoint.java | 64 +++++++++++++++++++ .../endpoint/mvc/GenericMvcEndpoint.java | 47 ++++++++++++++ .../endpoint/mvc/MetricsMvcEndpoint.java | 57 +++++++++++++++++ .../actuate/endpoint/mvc/MvcEndpoint.java | 26 ++++++++ .../endpoint/mvc/ShutdownMvcEndpoint.java | 40 ++++++++++++ .../actuate/endpoint/BeansEndpointTests.java | 11 +++- .../mvc/EndpointHandlerMappingTests.java | 34 ++++++---- 19 files changed, 363 insertions(+), 139 deletions(-) create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpoint.java create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/GenericMvcEndpoint.java create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MetricsMvcEndpoint.java create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoint.java create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ShutdownMvcEndpoint.java diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java index 3e46e0e1103..4eeddec69f0 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java @@ -17,6 +17,8 @@ package org.springframework.boot.actuate.autoconfigure; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; import javax.servlet.Filter; import javax.servlet.FilterChain; @@ -28,8 +30,19 @@ import javax.servlet.http.HttpServletResponse; import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.boot.actuate.endpoint.Endpoint; +import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint; +import org.springframework.boot.actuate.endpoint.MetricsEndpoint; +import org.springframework.boot.actuate.endpoint.ShutdownEndpoint; import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping; +import org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.GenericMvcEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.ShutdownMvcEndpoint; import org.springframework.boot.actuate.properties.ManagementServerProperties; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -50,6 +63,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Component; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.servlet.DispatcherServlet; @@ -119,6 +133,50 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware, }; } + @Component + protected static class GenericEndpointPostProcessor implements + BeanDefinitionRegistryPostProcessor { + + private BeanDefinitionRegistry registry; + + private Map>, Class> endpointTypes = new HashMap>, Class>(); + + public GenericEndpointPostProcessor() { + this.endpointTypes.put(EnvironmentEndpoint.class, + EnvironmentMvcEndpoint.class); + this.endpointTypes.put(MetricsEndpoint.class, MetricsMvcEndpoint.class); + this.endpointTypes.put(ShutdownEndpoint.class, ShutdownMvcEndpoint.class); + } + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) + throws BeansException { + for (String name : beanFactory.getBeanNamesForType(Endpoint.class)) { + Class type = getTypeForEndpoint(beanFactory.getType(name)); + BeanDefinitionBuilder bean = BeanDefinitionBuilder + .genericBeanDefinition(type); + bean.addConstructorArgReference(name); + this.registry.registerBeanDefinition("mvc." + name, + bean.getBeanDefinition()); + } + } + + protected Class getTypeForEndpoint(Class endpoint) { + Class type = GenericMvcEndpoint.class; + if (this.endpointTypes.containsKey(endpoint)) { + type = this.endpointTypes.get(endpoint); + } + return type; + } + + @Override + public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) + throws BeansException { + this.registry = registry; + } + + } + private void createChildManagementContext() { final AnnotationConfigEmbeddedWebApplicationContext childContext = new AnnotationConfigEmbeddedWebApplicationContext(); diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/BeansEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/BeansEndpoint.java index b07f3c9408a..03839574e77 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/BeansEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/BeansEndpoint.java @@ -16,16 +16,16 @@ package org.springframework.boot.actuate.endpoint; +import java.util.List; + import org.springframework.beans.BeansException; -import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; +import org.springframework.boot.config.JsonParser; +import org.springframework.boot.config.JsonParserFactory; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.support.LiveBeansView; import org.springframework.core.env.Environment; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; /** * Exposes JSON view of Spring beans. If the {@link Environment} contains a key setting @@ -36,12 +36,13 @@ import org.springframework.web.bind.annotation.ResponseBody; * @author Dave Syer */ @ConfigurationProperties(name = "endpoints.beans", ignoreUnknownFields = false) -@FrameworkEndpoint -public class BeansEndpoint extends AbstractEndpoint implements +public class BeansEndpoint extends AbstractEndpoint> implements ApplicationContextAware { private LiveBeansView liveBeansView = new LiveBeansView(); + private JsonParser parser = JsonParserFactory.getJsonParser(); + public BeansEndpoint() { super("/beans"); } @@ -55,9 +56,7 @@ public class BeansEndpoint extends AbstractEndpoint implements } @Override - @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseBody - public String invoke() { - return this.liveBeansView.getSnapshotAsJson(); + public List invoke() { + return this.parser.parseList(this.liveBeansView.getSnapshotAsJson()); } } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java index 95fa306e7c6..e6c1441e810 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java @@ -19,13 +19,10 @@ package org.springframework.boot.actuate.endpoint; import java.util.Map; import org.springframework.beans.BeansException; -import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.util.Assert; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; import com.fasterxml.jackson.databind.ObjectMapper; @@ -41,7 +38,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; * @author Christian Dupuis */ @ConfigurationProperties(name = "endpoints.configprops", ignoreUnknownFields = false) -@FrameworkEndpoint public class ConfigurationPropertiesReportEndpoint extends AbstractEndpoint> implements ApplicationContextAware { @@ -67,8 +63,7 @@ public class ConfigurationPropertiesReportEndpoint extends this.keysToSanitize = keysToSanitize; } - @RequestMapping - @ResponseBody + @Override public Map invoke() { Map beans = extract(this.context); return beans; diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/DumpEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/DumpEndpoint.java index 33d7f72a83b..7ac1744b9f3 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/DumpEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/DumpEndpoint.java @@ -21,10 +21,7 @@ import java.lang.management.ThreadInfo; import java.util.Arrays; import java.util.List; -import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; /** * {@link Endpoint} to expose thread info. @@ -32,7 +29,6 @@ import org.springframework.web.bind.annotation.ResponseBody; * @author Dave Syer */ @ConfigurationProperties(name = "endpoints.dump", ignoreUnknownFields = false) -@FrameworkEndpoint public class DumpEndpoint extends AbstractEndpoint> { /** @@ -43,8 +39,6 @@ public class DumpEndpoint extends AbstractEndpoint> { } @Override - @RequestMapping - @ResponseBody public List invoke() { return Arrays.asList(ManagementFactory.getThreadMXBean().dumpAllThreads(true, true)); diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpoint.java index a176d150d67..ea1b7671fff 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpoint.java @@ -19,7 +19,6 @@ package org.springframework.boot.actuate.endpoint; import java.util.LinkedHashMap; import java.util.Map; -import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.EnvironmentAware; import org.springframework.core.env.ConfigurableEnvironment; @@ -27,11 +26,6 @@ import org.springframework.core.env.EnumerablePropertySource; import org.springframework.core.env.Environment; import org.springframework.core.env.PropertySource; import org.springframework.core.env.StandardEnvironment; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.ResponseStatus; /** * {@link Endpoint} to expose {@link ConfigurableEnvironment environment} information. @@ -40,7 +34,6 @@ import org.springframework.web.bind.annotation.ResponseStatus; * @author Phillip Webb */ @ConfigurationProperties(name = "endpoints.env", ignoreUnknownFields = false) -@FrameworkEndpoint public class EnvironmentEndpoint extends AbstractEndpoint> implements EnvironmentAware { @@ -54,8 +47,6 @@ public class EnvironmentEndpoint extends AbstractEndpoint> i } @Override - @RequestMapping - @ResponseBody public Map invoke() { Map result = new LinkedHashMap(); result.put("profiles", this.environment.getActiveProfiles()); @@ -72,16 +63,6 @@ public class EnvironmentEndpoint extends AbstractEndpoint> i return result; } - @RequestMapping("/{name:.*}") - @ResponseBody - public Object value(@PathVariable String name) { - String result = this.environment.getProperty(name); - if (result == null) { - throw new NoSuchPropertyException("No such property: " + name); - } - return sanitize(name, result); - } - private Iterable> getPropertySources() { if (this.environment != null && this.environment instanceof ConfigurableEnvironment) { @@ -90,7 +71,7 @@ public class EnvironmentEndpoint extends AbstractEndpoint> i return new StandardEnvironment().getPropertySources(); } - private Object sanitize(String name, Object object) { + public static Object sanitize(String name, Object object) { if (name.toLowerCase().endsWith("password") || name.toLowerCase().endsWith("secret")) { return object == null ? null : "******"; @@ -103,13 +84,4 @@ public class EnvironmentEndpoint extends AbstractEndpoint> i this.environment = environment; } - @ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "No such property") - public static class NoSuchPropertyException extends RuntimeException { - - public NoSuchPropertyException(String string) { - super(string); - } - - } - } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/HealthEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/HealthEndpoint.java index 4ee546a542f..cc0ec319607 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/HealthEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/HealthEndpoint.java @@ -16,12 +16,9 @@ package org.springframework.boot.actuate.endpoint; -import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.util.Assert; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; /** * {@link Endpoint} to expose application health. @@ -29,7 +26,6 @@ import org.springframework.web.bind.annotation.ResponseBody; * @author Dave Syer */ @ConfigurationProperties(name = "endpoints.health", ignoreUnknownFields = false) -@FrameworkEndpoint public class HealthEndpoint extends AbstractEndpoint { private HealthIndicator indicator; @@ -50,8 +46,6 @@ public class HealthEndpoint extends AbstractEndpoint { } @Override - @RequestMapping - @ResponseBody public T invoke() { return this.indicator.health(); } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java index 27fc113ece7..4f996c6c90e 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java @@ -20,11 +20,8 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; -import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.util.Assert; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; /** * {@link Endpoint} to expose arbitrary application information. @@ -32,7 +29,6 @@ import org.springframework.web.bind.annotation.ResponseBody; * @author Dave Syer */ @ConfigurationProperties(name = "endpoints.info", ignoreUnknownFields = false) -@FrameworkEndpoint public class InfoEndpoint extends AbstractEndpoint> { private Map info; @@ -49,8 +45,6 @@ public class InfoEndpoint extends AbstractEndpoint> { } @Override - @RequestMapping - @ResponseBody public Map invoke() { Map info = new LinkedHashMap(this.info); info.putAll(getAdditionalInfo()); diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ManagementErrorEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ManagementErrorEndpoint.java index c7e57455246..441c59d147f 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ManagementErrorEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ManagementErrorEndpoint.java @@ -19,6 +19,7 @@ package org.springframework.boot.actuate.endpoint; import java.util.Map; import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint; import org.springframework.boot.actuate.web.ErrorController; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.web.bind.annotation.RequestMapping; @@ -33,22 +34,27 @@ import org.springframework.web.context.request.RequestContextHolder; * * @author Dave Syer */ -@FrameworkEndpoint @ConfigurationProperties(name = "error") -public class ManagementErrorEndpoint extends AbstractEndpoint> { +@FrameworkEndpoint +public class ManagementErrorEndpoint implements MvcEndpoint { private final ErrorController controller; + private String path; public ManagementErrorEndpoint(String path, ErrorController controller) { - super(path, false, true); + this.path = path; this.controller = controller; } - @Override @RequestMapping @ResponseBody public Map invoke() { RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); return this.controller.extract(attributes, false); } + + @Override + public String getPath() { + return this.path; + } } \ No newline at end of file diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/MetricsEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/MetricsEndpoint.java index 3e0b30331e7..fff41f266ce 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/MetricsEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/MetricsEndpoint.java @@ -19,15 +19,9 @@ package org.springframework.boot.actuate.endpoint; import java.util.LinkedHashMap; import java.util.Map; -import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; import org.springframework.boot.actuate.metrics.Metric; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.http.HttpStatus; import org.springframework.util.Assert; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.ResponseStatus; /** * {@link Endpoint} to expose {@link PublicMetrics}. @@ -35,7 +29,6 @@ import org.springframework.web.bind.annotation.ResponseStatus; * @author Dave Syer */ @ConfigurationProperties(name = "endpoints.metrics", ignoreUnknownFields = false) -@FrameworkEndpoint public class MetricsEndpoint extends AbstractEndpoint> { private PublicMetrics metrics; @@ -52,8 +45,6 @@ public class MetricsEndpoint extends AbstractEndpoint> { } @Override - @RequestMapping - @ResponseBody public Map invoke() { Map result = new LinkedHashMap(); for (Metric metric : this.metrics.metrics()) { @@ -62,22 +53,4 @@ public class MetricsEndpoint extends AbstractEndpoint> { return result; } - @RequestMapping("/{name:.*}") - @ResponseBody - public Object value(@PathVariable String name) { - Object value = invoke().get(name); - if (value == null) { - throw new NoSuchMetricException("No such metric: " + name); - } - return value; - } - - @ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "No such metric") - public static class NoSuchMetricException extends RuntimeException { - - public NoSuchMetricException(String string) { - super(string); - } - - } } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ShutdownEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ShutdownEndpoint.java index 9585a799efb..78ceec3bbf4 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ShutdownEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ShutdownEndpoint.java @@ -20,14 +20,10 @@ import java.util.Collections; import java.util.Map; import org.springframework.beans.BeansException; -import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.ResponseBody; /** * {@link Endpoint} to shutdown the {@link ApplicationContext}. @@ -36,7 +32,6 @@ import org.springframework.web.bind.annotation.ResponseBody; * @author Christian Dupuis */ @ConfigurationProperties(name = "endpoints.shutdown", ignoreUnknownFields = false) -@FrameworkEndpoint public class ShutdownEndpoint extends AbstractEndpoint> implements ApplicationContextAware { @@ -50,8 +45,6 @@ public class ShutdownEndpoint extends AbstractEndpoint> impl } @Override - @RequestMapping(method = RequestMethod.POST) - @ResponseBody public Map invoke() { if (this.context == null) { @@ -59,21 +52,26 @@ public class ShutdownEndpoint extends AbstractEndpoint> impl "No context to shutdown."); } - new Thread(new Runnable() { - @Override - public void run() { - try { - Thread.sleep(500L); - } - catch (InterruptedException ex) { - // Swallow exception and continue - } - ShutdownEndpoint.this.context.close(); - } - }).start(); + try { + return Collections. singletonMap("message", + "Shutting down, bye..."); + } + finally { - return Collections. singletonMap("message", - "Shutting down, bye..."); + new Thread(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(500L); + } + catch (InterruptedException ex) { + // Swallow exception and continue + } + ShutdownEndpoint.this.context.close(); + } + }).start(); + + } } @Override diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/TraceEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/TraceEndpoint.java index a003170af8f..02e51567bb2 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/TraceEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/TraceEndpoint.java @@ -18,13 +18,10 @@ package org.springframework.boot.actuate.endpoint; import java.util.List; -import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; import org.springframework.boot.actuate.trace.Trace; import org.springframework.boot.actuate.trace.TraceRepository; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.util.Assert; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; /** * {@link Endpoint} to expose {@link Trace} information. @@ -32,7 +29,6 @@ import org.springframework.web.bind.annotation.ResponseBody; * @author Dave Syer */ @ConfigurationProperties(name = "endpoints.trace", ignoreUnknownFields = false) -@FrameworkEndpoint public class TraceEndpoint extends AbstractEndpoint> { private TraceRepository repository; @@ -49,8 +45,6 @@ public class TraceEndpoint extends AbstractEndpoint> { } @Override - @RequestMapping - @ResponseBody public List invoke() { return this.repository.findAll(); } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java index 5263e36a3c6..74b810dafcb 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java @@ -117,8 +117,8 @@ public class EndpointHandlerMapping extends RequestMappingHandlerMapping impleme if (bean instanceof String) { bean = getApplicationContext().getBean((String) handler); } - if (bean instanceof Endpoint) { - Endpoint endpoint = (Endpoint) bean; + if (bean instanceof MvcEndpoint) { + MvcEndpoint endpoint = (MvcEndpoint) bean; path = endpoint.getPath(); } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpoint.java new file mode 100644 index 00000000000..09207d45764 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpoint.java @@ -0,0 +1,64 @@ +/* + * Copyright 2012-2013 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.endpoint.mvc; + +import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint; +import org.springframework.context.EnvironmentAware; +import org.springframework.core.env.Environment; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; + +/** + * @author Dave Syer + */ +@FrameworkEndpoint +public class EnvironmentMvcEndpoint extends GenericMvcEndpoint implements + EnvironmentAware { + + private Environment environment; + + public EnvironmentMvcEndpoint(EnvironmentEndpoint delegate) { + super(delegate); + } + + @RequestMapping("/{name:.*}") + @ResponseBody + public Object value(@PathVariable String name) { + String result = this.environment.getProperty(name); + if (result == null) { + throw new NoSuchPropertyException("No such property: " + name); + } + return EnvironmentEndpoint.sanitize(name, result); + } + + @Override + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "No such property") + public static class NoSuchPropertyException extends RuntimeException { + + public NoSuchPropertyException(String string) { + super(string); + } + + } +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/GenericMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/GenericMvcEndpoint.java new file mode 100644 index 00000000000..c8fa2e436bc --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/GenericMvcEndpoint.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2013 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.endpoint.mvc; + +import org.springframework.boot.actuate.endpoint.Endpoint; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + * @author Dave Syer + */ +@FrameworkEndpoint +public class GenericMvcEndpoint implements MvcEndpoint { + + private Endpoint delegate; + + public GenericMvcEndpoint(Endpoint delegate) { + this.delegate = delegate; + } + + @RequestMapping(method = RequestMethod.GET) + @ResponseBody + public Object invoke() { + return this.delegate.invoke(); + } + + @Override + public String getPath() { + return this.delegate.getPath(); + } + +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MetricsMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MetricsMvcEndpoint.java new file mode 100644 index 00000000000..14f72486f9a --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MetricsMvcEndpoint.java @@ -0,0 +1,57 @@ +/* + * Copyright 2012-2013 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.endpoint.mvc; + +import org.springframework.boot.actuate.endpoint.MetricsEndpoint; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; + +/** + * @author Dave Syer + */ +@FrameworkEndpoint +public class MetricsMvcEndpoint extends GenericMvcEndpoint { + + private MetricsEndpoint delegate; + + public MetricsMvcEndpoint(MetricsEndpoint delegate) { + super(delegate); + this.delegate = delegate; + } + + @RequestMapping("/{name:.*}") + @ResponseBody + public Object value(@PathVariable String name) { + Object value = this.delegate.invoke().get(name); + if (value == null) { + throw new NoSuchMetricException("No such metric: " + name); + } + return value; + } + + @ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "No such metric") + public static class NoSuchMetricException extends RuntimeException { + + public NoSuchMetricException(String string) { + super(string); + } + + } +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoint.java new file mode 100644 index 00000000000..8ea12bbea11 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoint.java @@ -0,0 +1,26 @@ +/* + * Copyright 2012-2013 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.endpoint.mvc; + +/** + * @author Dave Syer + */ +public interface MvcEndpoint { + + String getPath(); + +} \ No newline at end of file diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ShutdownMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ShutdownMvcEndpoint.java new file mode 100644 index 00000000000..d1dc2f31cb7 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ShutdownMvcEndpoint.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012-2013 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.endpoint.mvc; + +import org.springframework.boot.actuate.endpoint.ShutdownEndpoint; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + * @author Dave Syer + */ +@FrameworkEndpoint +public class ShutdownMvcEndpoint extends GenericMvcEndpoint { + + public ShutdownMvcEndpoint(ShutdownEndpoint delegate) { + super(delegate); + } + + @RequestMapping(method = RequestMethod.POST) + @ResponseBody + @Override + public Object invoke() { + return super.invoke(); + } +} diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/BeansEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/BeansEndpointTests.java index ac35cbd3cff..ab898fd64ee 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/BeansEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/BeansEndpointTests.java @@ -16,13 +16,16 @@ package org.springframework.boot.actuate.endpoint; +import java.util.List; +import java.util.Map; + import org.junit.Test; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import static org.hamcrest.Matchers.containsString; -import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** * Tests for {@link BeansEndpoint}. @@ -37,7 +40,9 @@ public class BeansEndpointTests extends AbstractEndpointTests { @Test public void invoke() throws Exception { - assertThat(getEndpointBean().invoke(), containsString("\"bean\": \"endpoint\"")); + List result = getEndpointBean().invoke(); + assertEquals(1, result.size()); + assertTrue(result.get(0) instanceof Map); } @Configuration diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMappingTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMappingTests.java index f18afa22281..741fea047c7 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMappingTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMappingTests.java @@ -52,13 +52,13 @@ public class EndpointHandlerMappingTests { this.context.getDefaultListableBeanFactory().registerSingleton("mapping", this.mapping); this.mapping.setApplicationContext(this.context); - this.method = ReflectionUtils.findMethod(TestEndpoint.class, "invoke"); + this.method = ReflectionUtils.findMethod(TestMvcEndpoint.class, "invoke"); } @Test public void withoutPrefix() throws Exception { - TestEndpoint endpointA = new TestEndpoint("/a"); - TestEndpoint endpointB = new TestEndpoint("/b"); + TestMvcEndpoint endpointA = new TestMvcEndpoint(new TestEndpoint("/a")); + TestMvcEndpoint endpointB = new TestMvcEndpoint(new TestEndpoint("/b")); this.context.getDefaultListableBeanFactory().registerSingleton( endpointA.getPath(), endpointA); this.context.getDefaultListableBeanFactory().registerSingleton( @@ -76,8 +76,8 @@ public class EndpointHandlerMappingTests { @Test public void withPrefix() throws Exception { - TestEndpoint endpointA = new TestEndpoint("/a"); - TestEndpoint endpointB = new TestEndpoint("/b"); + TestMvcEndpoint endpointA = new TestMvcEndpoint(new TestEndpoint("/a")); + TestMvcEndpoint endpointB = new TestMvcEndpoint(new TestEndpoint("/b")); this.context.getDefaultListableBeanFactory().registerSingleton( endpointA.getPath(), endpointA); this.context.getDefaultListableBeanFactory().registerSingleton( @@ -96,7 +96,7 @@ public class EndpointHandlerMappingTests { @Test(expected = HttpRequestMethodNotSupportedException.class) public void onlyGetHttpMethodForNonActionEndpoints() throws Exception { - TestEndpoint endpoint = new TestEndpoint("/a"); + TestMvcEndpoint endpoint = new TestActionEndpoint(new TestEndpoint("/a")); this.context.getDefaultListableBeanFactory().registerSingleton( endpoint.getPath(), endpoint); this.mapping.afterPropertiesSet(); @@ -106,7 +106,7 @@ public class EndpointHandlerMappingTests { @Test public void postHttpMethodForActionEndpoints() throws Exception { - TestEndpoint endpoint = new TestActionEndpoint("/a"); + TestMvcEndpoint endpoint = new TestActionEndpoint(new TestEndpoint("/a")); this.context.getDefaultListableBeanFactory().registerSingleton( endpoint.getPath(), endpoint); this.mapping.afterPropertiesSet(); @@ -115,7 +115,7 @@ public class EndpointHandlerMappingTests { @Test(expected = HttpRequestMethodNotSupportedException.class) public void onlyPostHttpMethodForActionEndpoints() throws Exception { - TestEndpoint endpoint = new TestActionEndpoint("/a"); + TestMvcEndpoint endpoint = new TestActionEndpoint(new TestEndpoint("/a")); this.context.getDefaultListableBeanFactory().registerSingleton( endpoint.getPath(), endpoint); this.mapping.afterPropertiesSet(); @@ -125,7 +125,7 @@ public class EndpointHandlerMappingTests { @Test public void disabled() throws Exception { - TestEndpoint endpoint = new TestEndpoint("/a"); + TestMvcEndpoint endpoint = new TestMvcEndpoint(new TestEndpoint("/a")); this.context.getDefaultListableBeanFactory().registerSingleton( endpoint.getPath(), endpoint); this.mapping.setDisabled(true); @@ -134,7 +134,6 @@ public class EndpointHandlerMappingTests { nullValue()); } - @FrameworkEndpoint private static class TestEndpoint extends AbstractEndpoint { public TestEndpoint(String path) { @@ -150,10 +149,19 @@ public class EndpointHandlerMappingTests { } @FrameworkEndpoint - private static class TestActionEndpoint extends TestEndpoint { + private static class TestMvcEndpoint extends GenericMvcEndpoint { - public TestActionEndpoint(String path) { - super(path); + public TestMvcEndpoint(TestEndpoint delegate) { + super(delegate); + } + + } + + @FrameworkEndpoint + private static class TestActionEndpoint extends TestMvcEndpoint { + + public TestActionEndpoint(TestEndpoint delegate) { + super(delegate); } @Override From 7f1264bb65bf2b5285fe81b20006b36b226b0426 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Wed, 18 Dec 2013 12:44:54 +0000 Subject: [PATCH 07/10] Replace @FrameworkEndpoint with MvcEndpoint interface --- .../EndpointWebMvcAutoConfiguration.java | 71 +++++--------- ...dpointWebMvcChildContextConfiguration.java | 20 ++-- .../ManagementSecurityAutoConfiguration.java | 3 +- .../AutoConfigurationReportEndpoint.java | 6 -- .../endpoint/mvc/EndpointHandlerMapping.java | 42 ++++----- .../endpoint/mvc/EnvironmentMvcEndpoint.java | 4 +- .../endpoint/mvc/FrameworkEndpoint.java | 34 ------- .../endpoint/mvc/GenericMvcEndpoint.java | 14 ++- .../{ => mvc}/ManagementErrorEndpoint.java | 15 ++- .../endpoint/mvc/MetricsMvcEndpoint.java | 4 +- .../actuate/endpoint/mvc/MvcEndpoint.java | 12 ++- .../actuate/endpoint/mvc/MvcEndpoints.java | 88 ++++++++++++++++++ .../endpoint/mvc/ShutdownMvcEndpoint.java | 1 - .../EndpointWebMvcAutoConfigurationTests.java | 27 ++++-- .../endpoint/EnvironmentEndpointTests.java | 1 - .../mvc/EndpointHandlerMappingTests.java | 91 +++++++++--------- .../mvc/EnvironmentMvcEndpointTests.java | 93 +++++++++++++++++++ 17 files changed, 336 insertions(+), 190 deletions(-) delete mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/FrameworkEndpoint.java rename spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/{ => mvc}/ManagementErrorEndpoint.java (90%) create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoints.java create mode 100644 spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpointTests.java diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java index 4eeddec69f0..fb381ea0064 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java @@ -17,8 +17,6 @@ package org.springframework.boot.actuate.autoconfigure; import java.io.IOException; -import java.util.HashMap; -import java.util.Map; import javax.servlet.Filter; import javax.servlet.FilterChain; @@ -30,23 +28,20 @@ import javax.servlet.http.HttpServletResponse; import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint; import org.springframework.boot.actuate.endpoint.MetricsEndpoint; import org.springframework.boot.actuate.endpoint.ShutdownEndpoint; import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping; import org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint; -import org.springframework.boot.actuate.endpoint.mvc.GenericMvcEndpoint; import org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoints; import org.springframework.boot.actuate.endpoint.mvc.ShutdownMvcEndpoint; import org.springframework.boot.actuate.properties.ManagementServerProperties; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; @@ -63,7 +58,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.ContextRefreshedEvent; -import org.springframework.stereotype.Component; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.servlet.DispatcherServlet; @@ -97,7 +91,8 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware, @Bean @ConditionalOnMissingBean public EndpointHandlerMapping endpointHandlerMapping() { - EndpointHandlerMapping mapping = new EndpointHandlerMapping(); + EndpointHandlerMapping mapping = new EndpointHandlerMapping(mvcEndpoints() + .getEndpoints()); mapping.setDisabled(ManagementServerPort.get(this.applicationContext) != ManagementServerPort.SAME); mapping.setPrefix(this.managementServerProperties.getContextPath()); return mapping; @@ -133,48 +128,28 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware, }; } - @Component - protected static class GenericEndpointPostProcessor implements - BeanDefinitionRegistryPostProcessor { + @Bean + @ConditionalOnMissingBean + public MvcEndpoints mvcEndpoints() { + return new MvcEndpoints(); + } - private BeanDefinitionRegistry registry; + @Bean + @ConditionalOnBean(EnvironmentEndpoint.class) + public EnvironmentMvcEndpoint environmentMvcEndpoint(EnvironmentEndpoint delegate) { + return new EnvironmentMvcEndpoint(delegate); + } - private Map>, Class> endpointTypes = new HashMap>, Class>(); - - public GenericEndpointPostProcessor() { - this.endpointTypes.put(EnvironmentEndpoint.class, - EnvironmentMvcEndpoint.class); - this.endpointTypes.put(MetricsEndpoint.class, MetricsMvcEndpoint.class); - this.endpointTypes.put(ShutdownEndpoint.class, ShutdownMvcEndpoint.class); - } - - @Override - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) - throws BeansException { - for (String name : beanFactory.getBeanNamesForType(Endpoint.class)) { - Class type = getTypeForEndpoint(beanFactory.getType(name)); - BeanDefinitionBuilder bean = BeanDefinitionBuilder - .genericBeanDefinition(type); - bean.addConstructorArgReference(name); - this.registry.registerBeanDefinition("mvc." + name, - bean.getBeanDefinition()); - } - } - - protected Class getTypeForEndpoint(Class endpoint) { - Class type = GenericMvcEndpoint.class; - if (this.endpointTypes.containsKey(endpoint)) { - type = this.endpointTypes.get(endpoint); - } - return type; - } - - @Override - public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) - throws BeansException { - this.registry = registry; - } + @Bean + @ConditionalOnBean(MetricsEndpoint.class) + public MetricsMvcEndpoint metricsMvcEndpoint(MetricsEndpoint delegate) { + return new MetricsMvcEndpoint(delegate); + } + @Bean + @ConditionalOnBean(ShutdownEndpoint.class) + public ShutdownMvcEndpoint shutdownMvcEndpoint(ShutdownEndpoint delegate) { + return new ShutdownMvcEndpoint(delegate); } private void createChildManagementContext() { diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java index 5d255ba854b..4fa3dee7f73 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java @@ -16,6 +16,9 @@ package org.springframework.boot.actuate.autoconfigure; +import java.util.HashSet; +import java.util.Set; + import javax.servlet.Filter; import org.springframework.beans.factory.BeanFactory; @@ -24,13 +27,16 @@ import org.springframework.beans.factory.HierarchicalBeanFactory; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.actuate.endpoint.ManagementErrorEndpoint; import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping; +import org.springframework.boot.actuate.endpoint.mvc.ManagementErrorEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoints; import org.springframework.boot.actuate.properties.ManagementServerProperties; import org.springframework.boot.actuate.web.ErrorController; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.SearchStrategy; +import org.springframework.boot.autoconfigure.web.HttpMessageConverters; import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainerFactory; import org.springframework.boot.context.embedded.EmbeddedServletContainer; import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; @@ -38,7 +44,6 @@ import org.springframework.boot.context.embedded.ErrorPage; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.web.client.RestTemplate; import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.HandlerAdapter; import org.springframework.web.servlet.HandlerMapping; @@ -99,16 +104,19 @@ public class EndpointWebMvcChildContextConfiguration { } @Bean - public HandlerAdapter handlerAdapter() { + public HandlerAdapter handlerAdapter(HttpMessageConverters converters) { // TODO: maybe this needs more configuration for non-basic response use cases RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter(); - adapter.setMessageConverters(new RestTemplate().getMessageConverters()); + adapter.setMessageConverters(converters.getConverters()); return adapter; } @Bean - public HandlerMapping handlerMapping() { - EndpointHandlerMapping mapping = new EndpointHandlerMapping(); + public HandlerMapping handlerMapping(MvcEndpoints endpoints, + ListableBeanFactory beanFactory) { + Set set = new HashSet(endpoints.getEndpoints()); + set.addAll(beanFactory.getBeansOfType(MvcEndpoint.class).values()); + EndpointHandlerMapping mapping = new EndpointHandlerMapping(set); // In a child context we definitely want to see the parent endpoints mapping.setDetectHandlerMethodsInAncestorContexts(true); return mapping; diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementSecurityAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementSecurityAutoConfiguration.java index 7de8a357d9a..b476d6e1647 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementSecurityAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementSecurityAutoConfiguration.java @@ -19,6 +19,7 @@ package org.springframework.boot.actuate.autoconfigure; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Set; import javax.annotation.PostConstruct; import javax.servlet.Filter; @@ -210,7 +211,7 @@ public class ManagementSecurityAutoConfiguration { return NO_PATHS; } - List> endpoints = endpointHandlerMapping.getEndpoints(); + Set> endpoints = endpointHandlerMapping.getEndpoints(); List paths = new ArrayList(endpoints.size()); for (Endpoint endpoint : endpoints) { if (endpoint.isSensitive() == secure) { diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpoint.java index a10237be0b8..967373fc2b2 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpoint.java @@ -21,7 +21,6 @@ import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.endpoint.AutoConfigurationReportEndpoint.Report; -import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; import org.springframework.boot.autoconfigure.AutoConfigurationReport; import org.springframework.boot.autoconfigure.AutoConfigurationReport.ConditionAndOutcome; import org.springframework.boot.autoconfigure.AutoConfigurationReport.ConditionAndOutcomes; @@ -32,8 +31,6 @@ import org.springframework.util.ClassUtils; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; import com.fasterxml.jackson.annotation.JsonPropertyOrder; @@ -45,7 +42,6 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder; * @author Dave Syer */ @ConfigurationProperties(name = "endpoints.autoconfig", ignoreUnknownFields = false) -@FrameworkEndpoint public class AutoConfigurationReportEndpoint extends AbstractEndpoint { @Autowired @@ -56,8 +52,6 @@ public class AutoConfigurationReportEndpoint extends AbstractEndpoint { } @Override - @RequestMapping - @ResponseBody public Report invoke() { return new Report(this.autoConfigurationReport); } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java index 74b810dafcb..8884a7e34d2 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java @@ -17,17 +17,13 @@ package org.springframework.boot.actuate.endpoint.mvc; import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.Collection; +import java.util.HashSet; import java.util.Set; -import org.springframework.beans.factory.BeanFactoryUtils; -import org.springframework.beans.factory.InitializingBean; import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; -import org.springframework.core.annotation.AnnotationUtils; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.servlet.HandlerMapping; @@ -56,9 +52,9 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl * */ public class EndpointHandlerMapping extends RequestMappingHandlerMapping implements - InitializingBean, ApplicationContextAware { + ApplicationContextAware { - private List> endpoints; + private Set endpoints; private String prefix = ""; @@ -67,8 +63,10 @@ public class EndpointHandlerMapping extends RequestMappingHandlerMapping impleme /** * Create a new {@link EndpointHandlerMapping} instance. All {@link Endpoint}s will be * detected from the {@link ApplicationContext}. + * @param endpoints */ - public EndpointHandlerMapping() { + public EndpointHandlerMapping(Collection endpoints) { + this.endpoints = new HashSet(endpoints); // By default the static resource handler mapping is LOWEST_PRECEDENCE - 1 setOrder(LOWEST_PRECEDENCE - 2); } @@ -76,28 +74,20 @@ public class EndpointHandlerMapping extends RequestMappingHandlerMapping impleme @Override public void afterPropertiesSet() { super.afterPropertiesSet(); - if (this.endpoints == null) { - this.endpoints = findEndpointBeans(); + if (!this.disabled) { + for (MvcEndpoint endpoint : this.endpoints) { + detectHandlerMethods(endpoint); + } } } - @SuppressWarnings({ "rawtypes", "unchecked" }) - private List> findEndpointBeans() { - return new ArrayList(BeanFactoryUtils.beansOfTypeIncludingAncestors( - getApplicationContext(), Endpoint.class).values()); - } - /** - * Detects @FrameworkEndpoint annotations in handler beans. - * - * @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#isHandler(java.lang.Class) + * Since all handler beans are passed into the constructor there is no need to detect + * anything here */ @Override protected boolean isHandler(Class beanType) { - if (this.disabled) { - return false; - } - return AnnotationUtils.findAnnotation(beanType, FrameworkEndpoint.class) != null; + return false; } @Override @@ -169,7 +159,7 @@ public class EndpointHandlerMapping extends RequestMappingHandlerMapping impleme /** * Return the endpoints */ - public List> getEndpoints() { - return Collections.unmodifiableList(this.endpoints); + public Set> getEndpoints() { + return this.endpoints; } } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpoint.java index 09207d45764..1eacc19b752 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpoint.java @@ -22,13 +22,13 @@ import org.springframework.core.env.Environment; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; /** * @author Dave Syer */ -@FrameworkEndpoint public class EnvironmentMvcEndpoint extends GenericMvcEndpoint implements EnvironmentAware { @@ -38,7 +38,7 @@ public class EnvironmentMvcEndpoint extends GenericMvcEndpoint implements super(delegate); } - @RequestMapping("/{name:.*}") + @RequestMapping(value = "/{name:.*}", method = RequestMethod.GET) @ResponseBody public Object value(@PathVariable String name) { String result = this.environment.getProperty(name); diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/FrameworkEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/FrameworkEndpoint.java deleted file mode 100644 index f1a37e72770..00000000000 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/FrameworkEndpoint.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2012-2013 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.endpoint.mvc; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.stereotype.Component; - -/** - * @author Dave Syer - */ -@Component -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface FrameworkEndpoint { - -} \ No newline at end of file diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/GenericMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/GenericMvcEndpoint.java index c8fa2e436bc..6b56625f9fa 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/GenericMvcEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/GenericMvcEndpoint.java @@ -24,7 +24,6 @@ import org.springframework.web.bind.annotation.ResponseBody; /** * @author Dave Syer */ -@FrameworkEndpoint public class GenericMvcEndpoint implements MvcEndpoint { private Endpoint delegate; @@ -44,4 +43,17 @@ public class GenericMvcEndpoint implements MvcEndpoint { return this.delegate.getPath(); } + @Override + public boolean isSensitive() { + return this.delegate.isSensitive(); + } + + @Override + public Class getEndpointType() { + @SuppressWarnings("unchecked") + Class> type = (Class>) this.delegate + .getClass(); + return type; + } + } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ManagementErrorEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ManagementErrorEndpoint.java similarity index 90% rename from spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ManagementErrorEndpoint.java rename to spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ManagementErrorEndpoint.java index 441c59d147f..5b9e120f9cb 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ManagementErrorEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ManagementErrorEndpoint.java @@ -14,12 +14,10 @@ * limitations under the License. */ -package org.springframework.boot.actuate.endpoint; +package org.springframework.boot.actuate.endpoint.mvc; import java.util.Map; -import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; -import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint; import org.springframework.boot.actuate.web.ErrorController; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.web.bind.annotation.RequestMapping; @@ -35,7 +33,6 @@ import org.springframework.web.context.request.RequestContextHolder; * @author Dave Syer */ @ConfigurationProperties(name = "error") -@FrameworkEndpoint public class ManagementErrorEndpoint implements MvcEndpoint { private final ErrorController controller; @@ -57,4 +54,14 @@ public class ManagementErrorEndpoint implements MvcEndpoint { public String getPath() { return this.path; } + + @Override + public boolean isSensitive() { + return false; + } + + @Override + public Class getEndpointType() { + return null; + } } \ No newline at end of file diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MetricsMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MetricsMvcEndpoint.java index 14f72486f9a..26800b5b892 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MetricsMvcEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MetricsMvcEndpoint.java @@ -20,13 +20,13 @@ import org.springframework.boot.actuate.endpoint.MetricsEndpoint; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; /** * @author Dave Syer */ -@FrameworkEndpoint public class MetricsMvcEndpoint extends GenericMvcEndpoint { private MetricsEndpoint delegate; @@ -36,7 +36,7 @@ public class MetricsMvcEndpoint extends GenericMvcEndpoint { this.delegate = delegate; } - @RequestMapping("/{name:.*}") + @RequestMapping(value = "/{name:.*}", method = RequestMethod.GET) @ResponseBody public Object value(@PathVariable String name) { Object value = this.delegate.invoke().get(name); diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoint.java index 8ea12bbea11..19225dcc51a 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoint.java @@ -16,11 +16,19 @@ package org.springframework.boot.actuate.endpoint.mvc; +import org.springframework.boot.actuate.endpoint.Endpoint; + /** + * A strategy for the MVC layer on top of an {@link Endpoint}. Implementations are allowed + * to use @RequestMapping and the full Spring MVC machinery, but should not + * use @Controller or @RequestMapping at the type level (since + * that would lead to a double mapping of paths, once by the regular MVC handler mappings + * and once by the {@link EndpointHandlerMapping}). + * * @author Dave Syer */ -public interface MvcEndpoint { +public interface MvcEndpoint extends Endpoint { - String getPath(); + Class getEndpointType(); } \ No newline at end of file diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoints.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoints.java new file mode 100644 index 00000000000..3e1801b45c8 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoints.java @@ -0,0 +1,88 @@ +/* + * Copyright 2012-2013 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.endpoint.mvc; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.boot.actuate.endpoint.Endpoint; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +/** + * A registry for all {@link MvcEndpoint} beans, and a factory for a set of generic ones + * wrapping existing {@link Endpoint} instances that are not already exposed as MVC + * endpoints. + * + * @author Dave Syer + */ +@Component +public class MvcEndpoints implements ApplicationContextAware, InitializingBean { + + private ApplicationContext applicationContext; + + private Set endpoints = new HashSet(); + + private Set> customTypes; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + this.applicationContext = applicationContext; + } + + @Override + public void afterPropertiesSet() throws Exception { + Collection existing = this.applicationContext.getBeansOfType( + MvcEndpoint.class).values(); + this.endpoints.addAll(existing); + this.customTypes = findEndpointClasses(existing); + @SuppressWarnings("rawtypes") + Collection delegates = this.applicationContext.getBeansOfType( + Endpoint.class).values(); + for (Endpoint endpoint : delegates) { + if (isGenericEndpoint(endpoint.getClass())) { + this.endpoints.add(new GenericMvcEndpoint(endpoint)); + } + } + } + + private Set> findEndpointClasses(Collection existing) { + Set> types = new HashSet>(); + for (MvcEndpoint endpoint : existing) { + Class type = endpoint.getEndpointType(); + if (type != null) { + types.add(type); + } + } + return types; + } + + public Set getEndpoints() { + return this.endpoints; + } + + private boolean isGenericEndpoint(Class type) { + return !this.customTypes.contains(type) + && !MvcEndpoint.class.isAssignableFrom(type); + } + +} \ No newline at end of file diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ShutdownMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ShutdownMvcEndpoint.java index d1dc2f31cb7..0877ed6885e 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ShutdownMvcEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ShutdownMvcEndpoint.java @@ -24,7 +24,6 @@ import org.springframework.web.bind.annotation.ResponseBody; /** * @author Dave Syer */ -@FrameworkEndpoint public class ShutdownMvcEndpoint extends GenericMvcEndpoint { public ShutdownMvcEndpoint(ShutdownEndpoint delegate) { diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java index 521a4f587d3..5f7ece55b54 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java @@ -24,8 +24,8 @@ import java.nio.charset.Charset; import org.junit.After; import org.junit.Test; import org.springframework.boot.TestUtils; -import org.springframework.boot.actuate.endpoint.AbstractEndpoint; -import org.springframework.boot.actuate.endpoint.mvc.FrameworkEndpoint; +import org.springframework.boot.actuate.endpoint.Endpoint; +import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint; import org.springframework.boot.actuate.properties.ManagementServerProperties; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration; @@ -240,20 +240,29 @@ public class EndpointWebMvcAutoConfigurationTests { } - @FrameworkEndpoint - public static class TestEndpoint extends AbstractEndpoint { + public static class TestEndpoint implements MvcEndpoint { - public TestEndpoint() { - super("/endpoint", false, true); - } - - @Override @RequestMapping @ResponseBody public String invoke() { return "endpointoutput"; } + @Override + public String getPath() { + return "/endpoint"; + } + + @Override + public boolean isSensitive() { + return true; + } + + @Override + public Class getEndpointType() { + return Endpoint.class; + } + } } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpointTests.java index 133e897f68a..081cf162be8 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpointTests.java @@ -17,7 +17,6 @@ package org.springframework.boot.actuate.endpoint; import org.junit.Test; -import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMappingTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMappingTests.java index 741fea047c7..d40f34b9c87 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMappingTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMappingTests.java @@ -17,6 +17,7 @@ package org.springframework.boot.actuate.endpoint.mvc; import java.lang.reflect.Method; +import java.util.Arrays; import org.junit.Before; import org.junit.Test; @@ -44,14 +45,10 @@ import static org.junit.Assert.assertThat; public class EndpointHandlerMappingTests { private StaticApplicationContext context = new StaticApplicationContext(); - private EndpointHandlerMapping mapping = new EndpointHandlerMapping(); private Method method; @Before public void init() throws Exception { - this.context.getDefaultListableBeanFactory().registerSingleton("mapping", - this.mapping); - this.mapping.setApplicationContext(this.context); this.method = ReflectionUtils.findMethod(TestMvcEndpoint.class, "invoke"); } @@ -59,18 +56,17 @@ public class EndpointHandlerMappingTests { public void withoutPrefix() throws Exception { TestMvcEndpoint endpointA = new TestMvcEndpoint(new TestEndpoint("/a")); TestMvcEndpoint endpointB = new TestMvcEndpoint(new TestEndpoint("/b")); - this.context.getDefaultListableBeanFactory().registerSingleton( - endpointA.getPath(), endpointA); - this.context.getDefaultListableBeanFactory().registerSingleton( - endpointB.getPath(), endpointB); - this.mapping.afterPropertiesSet(); - assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a")) + EndpointHandlerMapping mapping = new EndpointHandlerMapping(Arrays.asList( + endpointA, endpointB)); + mapping.setApplicationContext(this.context); + mapping.afterPropertiesSet(); + assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/a")) .getHandler(), equalTo((Object) new HandlerMethod(endpointA, this.method))); - assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/b")) + assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/b")) .getHandler(), equalTo((Object) new HandlerMethod(endpointB, this.method))); - assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/c")), + assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/c")), nullValue()); } @@ -78,59 +74,62 @@ public class EndpointHandlerMappingTests { public void withPrefix() throws Exception { TestMvcEndpoint endpointA = new TestMvcEndpoint(new TestEndpoint("/a")); TestMvcEndpoint endpointB = new TestMvcEndpoint(new TestEndpoint("/b")); - this.context.getDefaultListableBeanFactory().registerSingleton( - endpointA.getPath(), endpointA); - this.context.getDefaultListableBeanFactory().registerSingleton( - endpointB.getPath(), endpointB); - this.mapping.setPrefix("/a"); - this.mapping.afterPropertiesSet(); - assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a/a")) + EndpointHandlerMapping mapping = new EndpointHandlerMapping(Arrays.asList( + endpointA, endpointB)); + mapping.setApplicationContext(this.context); + mapping.setPrefix("/a"); + mapping.afterPropertiesSet(); + assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/a/a")) .getHandler(), equalTo((Object) new HandlerMethod(endpointA, this.method))); - assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a/b")) + assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/a/b")) .getHandler(), equalTo((Object) new HandlerMethod(endpointB, this.method))); - assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a")), + assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/a")), nullValue()); } @Test(expected = HttpRequestMethodNotSupportedException.class) public void onlyGetHttpMethodForNonActionEndpoints() throws Exception { - TestMvcEndpoint endpoint = new TestActionEndpoint(new TestEndpoint("/a")); - this.context.getDefaultListableBeanFactory().registerSingleton( - endpoint.getPath(), endpoint); - this.mapping.afterPropertiesSet(); - assertNotNull(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a"))); - assertNull(this.mapping.getHandler(new MockHttpServletRequest("POST", "/a"))); + TestActionEndpoint endpoint = new TestActionEndpoint(new TestEndpoint("/a")); + EndpointHandlerMapping mapping = new EndpointHandlerMapping( + Arrays.asList(endpoint)); + mapping.setApplicationContext(this.context); + mapping.afterPropertiesSet(); + assertNotNull(mapping.getHandler(new MockHttpServletRequest("GET", "/a"))); + assertNull(mapping.getHandler(new MockHttpServletRequest("POST", "/a"))); } @Test public void postHttpMethodForActionEndpoints() throws Exception { - TestMvcEndpoint endpoint = new TestActionEndpoint(new TestEndpoint("/a")); - this.context.getDefaultListableBeanFactory().registerSingleton( - endpoint.getPath(), endpoint); - this.mapping.afterPropertiesSet(); - assertNotNull(this.mapping.getHandler(new MockHttpServletRequest("POST", "/a"))); + TestActionEndpoint endpoint = new TestActionEndpoint(new TestEndpoint("/a")); + EndpointHandlerMapping mapping = new EndpointHandlerMapping( + Arrays.asList(endpoint)); + mapping.setApplicationContext(this.context); + mapping.afterPropertiesSet(); + assertNotNull(mapping.getHandler(new MockHttpServletRequest("POST", "/a"))); } @Test(expected = HttpRequestMethodNotSupportedException.class) public void onlyPostHttpMethodForActionEndpoints() throws Exception { - TestMvcEndpoint endpoint = new TestActionEndpoint(new TestEndpoint("/a")); - this.context.getDefaultListableBeanFactory().registerSingleton( - endpoint.getPath(), endpoint); - this.mapping.afterPropertiesSet(); - assertNotNull(this.mapping.getHandler(new MockHttpServletRequest("POST", "/a"))); - assertNull(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a"))); + TestActionEndpoint endpoint = new TestActionEndpoint(new TestEndpoint("/a")); + EndpointHandlerMapping mapping = new EndpointHandlerMapping( + Arrays.asList(endpoint)); + mapping.setApplicationContext(this.context); + mapping.afterPropertiesSet(); + assertNotNull(mapping.getHandler(new MockHttpServletRequest("POST", "/a"))); + assertNull(mapping.getHandler(new MockHttpServletRequest("GET", "/a"))); } @Test public void disabled() throws Exception { TestMvcEndpoint endpoint = new TestMvcEndpoint(new TestEndpoint("/a")); - this.context.getDefaultListableBeanFactory().registerSingleton( - endpoint.getPath(), endpoint); - this.mapping.setDisabled(true); - this.mapping.afterPropertiesSet(); - assertThat(this.mapping.getHandler(new MockHttpServletRequest("GET", "/a")), + EndpointHandlerMapping mapping = new EndpointHandlerMapping( + Arrays.asList(endpoint)); + mapping.setDisabled(true); + mapping.setApplicationContext(this.context); + mapping.afterPropertiesSet(); + assertThat(mapping.getHandler(new MockHttpServletRequest("GET", "/a")), nullValue()); } @@ -141,14 +140,12 @@ public class EndpointHandlerMappingTests { } @Override - @RequestMapping(method = RequestMethod.GET) public Object invoke() { return null; } } - @FrameworkEndpoint private static class TestMvcEndpoint extends GenericMvcEndpoint { public TestMvcEndpoint(TestEndpoint delegate) { @@ -157,8 +154,7 @@ public class EndpointHandlerMappingTests { } - @FrameworkEndpoint - private static class TestActionEndpoint extends TestMvcEndpoint { + private static class TestActionEndpoint extends GenericMvcEndpoint { public TestActionEndpoint(TestEndpoint delegate) { super(delegate); @@ -169,6 +165,7 @@ public class EndpointHandlerMappingTests { public Object invoke() { return null; } + } } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpointTests.java new file mode 100644 index 00000000000..79a9f4cd6e2 --- /dev/null +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EnvironmentMvcEndpointTests.java @@ -0,0 +1,93 @@ +/* + * Copyright 2012-2013 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.endpoint.mvc; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.TestUtils; +import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration; +import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpointTests.TestConfiguration; +import org.springframework.boot.test.SpringApplicationConfiguration; +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.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalToIgnoringCase; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * @author Dave Syer + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = { TestConfiguration.class }) +@WebAppConfiguration +public class EnvironmentMvcEndpointTests { + + @Autowired + private WebApplicationContext context; + + private MockMvc mvc; + + @Before + public void setUp() { + this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build(); + TestUtils.addEnviroment((ConfigurableApplicationContext) this.context, "foo:bar"); + } + + @Test + public void home() throws Exception { + this.mvc.perform(get("/env")).andExpect(status().isOk()) + .andExpect(content().string(containsString("systemProperties"))); + } + + @Test + public void sub() throws Exception { + this.mvc.perform(get("/env/foo")).andExpect(status().isOk()) + .andExpect(content().string(equalToIgnoringCase("bar"))); + } + + @Import(EndpointWebMvcAutoConfiguration.class) + @EnableWebMvc + @Configuration + public static class TestConfiguration { + + @Bean + public EnvironmentEndpoint endpoint() { + return new EnvironmentEndpoint(); + } + + @Bean + public EnvironmentMvcEndpoint mvcEndpoint() { + return new EnvironmentMvcEndpoint(endpoint()); + } + + } + +} From 451acb5679dd95e19bd3b9e7318ee09082956a37 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Wed, 18 Dec 2013 14:37:30 +0000 Subject: [PATCH 08/10] Move JolokiaEndpoint so it is not an Endpoint --- .../JolokiaAutoConfiguration.java | 18 +++--- .../ManagementSecurityAutoConfiguration.java | 5 +- .../endpoint/EndpointDisabledException.java | 26 -------- .../endpoint/mvc/EndpointHandlerMapping.java | 2 +- .../JolokiaMvcEndpoint.java} | 48 ++++++++++++-- .../actuate/endpoint/mvc/MvcEndpoint.java | 6 +- .../JolokiaAutoConfigurationTests.java | 12 +++- .../endpoint/JolokiaEndpointTests.java | 42 ------------ .../endpoint/mvc/JolokiaEndpointTests.java | 64 +++++++++++++++++++ 9 files changed, 135 insertions(+), 88 deletions(-) delete mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EndpointDisabledException.java rename spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/{JolokiaEndpoint.java => mvc/JolokiaMvcEndpoint.java} (51%) delete mode 100644 spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/JolokiaEndpointTests.java create mode 100644 spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaEndpointTests.java diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/JolokiaAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/JolokiaAutoConfiguration.java index 030e04f235e..9e4e5eb6cc4 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/JolokiaAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/JolokiaAutoConfiguration.java @@ -20,7 +20,8 @@ import java.util.Map; import org.jolokia.http.AgentServlet; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.actuate.endpoint.JolokiaEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.JolokiaMvcEndpoint; +import org.springframework.boot.actuate.properties.ManagementServerProperties; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -65,6 +66,9 @@ public class JolokiaAutoConfiguration { private RelaxedPropertyResolver environment; + @Autowired + private ManagementServerProperties management; + @Autowired public void setEnvironment(Environment environment) { this.environment = new RelaxedPropertyResolver(environment); @@ -77,19 +81,17 @@ public class JolokiaAutoConfiguration { } @Bean - @ConditionalOnMissingBean() - public ServletRegistrationBean jolokiaServletRegistration() { - ServletRegistrationBean registrationBean = new ServletRegistrationBean( - jolokiaServlet(), this.environment.getProperty("endpoints.jolokia.path", - "/jolokia") + "/*"); + public ServletRegistrationBean jolokiaServletRegistration(AgentServlet servlet) { + ServletRegistrationBean registrationBean = new ServletRegistrationBean(servlet, + this.management.getContextPath() + jolokiaEndpoint().getPath() + "/*"); addInitParameters(registrationBean); return registrationBean; } @Bean @ConditionalOnMissingBean - public JolokiaEndpoint jolokiaEndpoint() { - return new JolokiaEndpoint(); + public JolokiaMvcEndpoint jolokiaEndpoint() { + return new JolokiaMvcEndpoint(); } protected void addInitParameters(ServletRegistrationBean registrationBean) { diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementSecurityAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementSecurityAutoConfiguration.java index b476d6e1647..c8faa74e3d1 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementSecurityAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementSecurityAutoConfiguration.java @@ -27,6 +27,7 @@ import javax.servlet.Filter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping; +import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint; import org.springframework.boot.actuate.properties.ManagementServerProperties; import org.springframework.boot.actuate.web.ErrorController; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -211,9 +212,9 @@ public class ManagementSecurityAutoConfiguration { return NO_PATHS; } - Set> endpoints = endpointHandlerMapping.getEndpoints(); + Set endpoints = endpointHandlerMapping.getEndpoints(); List paths = new ArrayList(endpoints.size()); - for (Endpoint endpoint : endpoints) { + for (MvcEndpoint endpoint : endpoints) { if (endpoint.isSensitive() == secure) { paths.add(endpoint.getPath()); } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EndpointDisabledException.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EndpointDisabledException.java deleted file mode 100644 index 2dce8a76f4d..00000000000 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EndpointDisabledException.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2013 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.endpoint; - -/** - * {@link RuntimeException} indicating an {@link Endpoint} implementation is not enabled. - * - * @author Christian Dupuis - */ -public class EndpointDisabledException extends RuntimeException { - -} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java index 8884a7e34d2..41fe81e9082 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java @@ -159,7 +159,7 @@ public class EndpointHandlerMapping extends RequestMappingHandlerMapping impleme /** * Return the endpoints */ - public Set> getEndpoints() { + public Set getEndpoints() { return this.endpoints; } } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/JolokiaEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpoint.java similarity index 51% rename from spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/JolokiaEndpoint.java rename to spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpoint.java index 9d394087991..1d0473cdcb4 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/JolokiaEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpoint.java @@ -14,8 +14,12 @@ * limitations under the License. */ -package org.springframework.boot.actuate.endpoint; +package org.springframework.boot.actuate.endpoint.mvc; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; + +import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.context.properties.ConfigurationProperties; /** @@ -25,14 +29,48 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * @author Christian Dupuis */ @ConfigurationProperties(name = "endpoints.jolokia", ignoreUnknownFields = false) -public class JolokiaEndpoint extends AbstractEndpoint { +public class JolokiaMvcEndpoint implements MvcEndpoint { - public JolokiaEndpoint() { - super("/jolokia"); + @NotNull + @Pattern(regexp = "/[^/]*", message = "Path must start with /") + private String path; + + private boolean sensitive; + + private boolean enabled = true; + + public JolokiaMvcEndpoint() { + this.path = "/jolokia"; + } + + public boolean isEnabled() { + return this.enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; } @Override - public String invoke() { + public String getPath() { + return this.path; + } + + public void setPath(String path) { + this.path = path; + } + + @Override + public boolean isSensitive() { + return this.sensitive; + } + + public void setSensitive(boolean sensitive) { + this.sensitive = sensitive; + } + + @Override + public Class getEndpointType() { return null; } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoint.java index 19225dcc51a..7aa76420f7c 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoint.java @@ -27,7 +27,11 @@ import org.springframework.boot.actuate.endpoint.Endpoint; * * @author Dave Syer */ -public interface MvcEndpoint extends Endpoint { +public interface MvcEndpoint { + + String getPath(); + + boolean isSensitive(); Class getEndpointType(); diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/JolokiaAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/JolokiaAutoConfigurationTests.java index efc159fc4ca..de66bf45d46 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/JolokiaAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/JolokiaAutoConfigurationTests.java @@ -60,7 +60,9 @@ public class JolokiaAutoConfigurationTests { public void agentServletRegisteredWithAppContext() throws Exception { this.context = new AnnotationConfigEmbeddedWebApplicationContext(); this.context.register(Config.class, WebMvcAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, JolokiaAutoConfiguration.class); + ManagementServerPropertiesAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + JolokiaAutoConfiguration.class); this.context.refresh(); assertEquals(1, this.context.getBeanNamesForType(AgentServlet.class).length); } @@ -70,7 +72,9 @@ public class JolokiaAutoConfigurationTests { this.context = new AnnotationConfigEmbeddedWebApplicationContext(); TestUtils.addEnviroment(this.context, "endpoints.jolokia.enabled:false"); this.context.register(Config.class, WebMvcAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, JolokiaAutoConfiguration.class); + ManagementServerPropertiesAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + JolokiaAutoConfiguration.class); this.context.refresh(); assertEquals(0, this.context.getBeanNamesForType(AgentServlet.class).length); } @@ -79,7 +83,9 @@ public class JolokiaAutoConfigurationTests { public void agentServletRegisteredWithServletContainer() throws Exception { this.context = new AnnotationConfigEmbeddedWebApplicationContext(); this.context.register(Config.class, WebMvcAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, JolokiaAutoConfiguration.class); + ManagementServerPropertiesAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + JolokiaAutoConfiguration.class); this.context.refresh(); Servlet servlet = null; diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/JolokiaEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/JolokiaEndpointTests.java deleted file mode 100644 index 99485f02d57..00000000000 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/JolokiaEndpointTests.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2013 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.endpoint; - -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * @author Christian Dupuis - */ -public class JolokiaEndpointTests extends AbstractEndpointTests { - - public JolokiaEndpointTests() { - super(Config.class, JolokiaEndpoint.class, "/jolokia", true, "endpoints.jolokia"); - } - - @Configuration - @EnableConfigurationProperties - public static class Config { - - @Bean - public JolokiaEndpoint endpoint() { - return new JolokiaEndpoint(); - } - - } -} diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaEndpointTests.java new file mode 100644 index 00000000000..318a83adb70 --- /dev/null +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaEndpointTests.java @@ -0,0 +1,64 @@ +/* + * Copyright 2013 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.endpoint.mvc; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration; +import org.springframework.boot.actuate.endpoint.mvc.JolokiaEndpointTests.Config; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +import static org.junit.Assert.assertEquals; + +/** + * @author Christian Dupuis + * @author Dave Syer + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = { Config.class }) +@WebAppConfiguration +public class JolokiaEndpointTests { + + @Autowired + private MvcEndpoints endpoints; + + @Test + public void endpointRegistered() throws Exception { + assertEquals(1, this.endpoints.getEndpoints().size()); + } + + @Configuration + @EnableConfigurationProperties + @EnableWebMvc + @Import(EndpointWebMvcAutoConfiguration.class) + public static class Config { + + @Bean + public JolokiaMvcEndpoint endpoint() { + return new JolokiaMvcEndpoint(); + } + + } +} From 43b820a7d3493d1b931dcc9b2b75b2e6208a164c Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 18 Dec 2013 21:00:37 -0800 Subject: [PATCH 09/10] Rename Endpoint path to ID --- .../actuate/endpoint/AbstractEndpoint.java | 30 +++++++++---------- .../AutoConfigurationReportEndpoint.java | 2 +- .../boot/actuate/endpoint/BeansEndpoint.java | 2 +- ...ConfigurationPropertiesReportEndpoint.java | 2 +- .../boot/actuate/endpoint/DumpEndpoint.java | 2 +- .../boot/actuate/endpoint/Endpoint.java | 13 +++++--- .../actuate/endpoint/EnvironmentEndpoint.java | 2 +- .../boot/actuate/endpoint/HealthEndpoint.java | 6 +--- .../boot/actuate/endpoint/InfoEndpoint.java | 2 +- .../actuate/endpoint/MetricsEndpoint.java | 2 +- .../actuate/endpoint/ShutdownEndpoint.java | 2 +- .../boot/actuate/endpoint/TraceEndpoint.java | 2 +- .../endpoint/mvc/EndpointHandlerMapping.java | 2 +- .../endpoint/mvc/GenericMvcEndpoint.java | 2 +- .../endpoint/AbstractEndpointTests.java | 16 +++++----- .../AutoConfigurationReportEndpointTests.java | 2 +- .../actuate/endpoint/BeansEndpointTests.java | 2 +- ...gurationPropertiesReportEndpointTests.java | 2 +- .../actuate/endpoint/DumpEndpointTests.java | 3 +- .../endpoint/EnvironmentEndpointTests.java | 2 +- .../actuate/endpoint/HealthEndpointTests.java | 3 +- .../actuate/endpoint/InfoEndpointTests.java | 2 +- .../endpoint/MetricsEndpointTests.java | 4 +-- .../endpoint/ShutdownEndpointTests.java | 2 +- .../actuate/endpoint/TraceEndpointTests.java | 3 +- .../jmx/EndpointMBeanExporterTests.java | 4 +-- 26 files changed, 56 insertions(+), 60 deletions(-) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AbstractEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AbstractEndpoint.java index 221bd36c714..717f5a905a7 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AbstractEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AbstractEndpoint.java @@ -29,23 +29,32 @@ import javax.validation.constraints.Pattern; public abstract class AbstractEndpoint implements Endpoint { @NotNull - @Pattern(regexp = "/[^/]*", message = "Path must start with /") - private String path; + @Pattern(regexp = "\\w+", message = "ID must only contains letters, numbers and '_'") + private String id; private boolean sensitive; private boolean enabled = true; - public AbstractEndpoint(String path) { - this(path, true, true); + public AbstractEndpoint(String id) { + this(id, true, true); } - public AbstractEndpoint(String path, boolean sensitive, boolean enabled) { - this.path = path; + public AbstractEndpoint(String id, boolean sensitive, boolean enabled) { + this.id = id; this.sensitive = sensitive; this.enabled = enabled; } + @Override + public String getId() { + return this.id; + } + + public void setId(String id) { + this.id = id; + } + public boolean isEnabled() { return this.enabled; } @@ -54,15 +63,6 @@ public abstract class AbstractEndpoint implements Endpoint { this.enabled = enabled; } - @Override - public String getPath() { - return this.path; - } - - public void setPath(String path) { - this.path = path; - } - @Override public boolean isSensitive() { return this.sensitive; diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpoint.java index 967373fc2b2..7afbce612ee 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpoint.java @@ -48,7 +48,7 @@ public class AutoConfigurationReportEndpoint extends AbstractEndpoint { private AutoConfigurationReport autoConfigurationReport; public AutoConfigurationReportEndpoint() { - super("/autoconfig"); + super("autoconfig"); } @Override diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/BeansEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/BeansEndpoint.java index 03839574e77..83fed278c85 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/BeansEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/BeansEndpoint.java @@ -44,7 +44,7 @@ public class BeansEndpoint extends AbstractEndpoint> implements private JsonParser parser = JsonParserFactory.getJsonParser(); public BeansEndpoint() { - super("/beans"); + super("beans"); } @Override diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java index e6c1441e810..00fae013a11 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java @@ -46,7 +46,7 @@ public class ConfigurationPropertiesReportEndpoint extends private ApplicationContext context; public ConfigurationPropertiesReportEndpoint() { - super("/configprops"); + super("configprops"); } @Override diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/DumpEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/DumpEndpoint.java index 7ac1744b9f3..26ac45e35ea 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/DumpEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/DumpEndpoint.java @@ -35,7 +35,7 @@ public class DumpEndpoint extends AbstractEndpoint> { * Create a new {@link DumpEndpoint} instance. */ public DumpEndpoint() { - super("/dump"); + super("dump"); } @Override diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Endpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Endpoint.java index 6a541238922..591ed9bd905 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Endpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Endpoint.java @@ -27,13 +27,18 @@ package org.springframework.boot.actuate.endpoint; public interface Endpoint { /** - * Returns the path of the endpoint. Must start with '/' and should not include - * wildcards. + * The logical ID of the endpoint. Must only contain simple letters, numbers and '_' + * characters (ie a {@literal "\w"} regex). */ - String getPath(); + String getId(); /** - * Returns if the endpoint is sensitive, i.e. may return data that the average user + * Return if the endpoint is enabled. + */ + boolean isEnabled(); + + /** + * Return if the endpoint is sensitive, i.e. may return data that the average user * should not see. Mappings can use this as a security hint. */ boolean isSensitive(); diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpoint.java index ea1b7671fff..649d9d0a861 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpoint.java @@ -43,7 +43,7 @@ public class EnvironmentEndpoint extends AbstractEndpoint> i * Create a new {@link EnvironmentEndpoint} instance. */ public EnvironmentEndpoint() { - super("/env"); + super("env"); } @Override diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/HealthEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/HealthEndpoint.java index cc0ec319607..6821bb24146 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/HealthEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/HealthEndpoint.java @@ -36,15 +36,11 @@ public class HealthEndpoint extends AbstractEndpoint { * @param indicator the health indicator */ public HealthEndpoint(HealthIndicator indicator) { - super("/health", false, true); + super("health", false, true); Assert.notNull(indicator, "Indicator must not be null"); this.indicator = indicator; } - HealthEndpoint() { - super("/health", false, true); - } - @Override public T invoke() { return this.indicator.health(); diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java index 4f996c6c90e..a9ce11b6c69 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java @@ -39,7 +39,7 @@ public class InfoEndpoint extends AbstractEndpoint> { * @param info the info to expose */ public InfoEndpoint(Map info) { - super("/info", false, true); + super("info", false, true); Assert.notNull(info, "Info must not be null"); this.info = info; } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/MetricsEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/MetricsEndpoint.java index fff41f266ce..bd41c270ffa 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/MetricsEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/MetricsEndpoint.java @@ -39,7 +39,7 @@ public class MetricsEndpoint extends AbstractEndpoint> { * @param metrics the metrics to expose */ public MetricsEndpoint(PublicMetrics metrics) { - super("/metrics"); + super("metrics"); Assert.notNull(metrics, "Metrics must not be null"); this.metrics = metrics; } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ShutdownEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ShutdownEndpoint.java index 78ceec3bbf4..ad814e70c16 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ShutdownEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ShutdownEndpoint.java @@ -41,7 +41,7 @@ public class ShutdownEndpoint extends AbstractEndpoint> impl * Create a new {@link ShutdownEndpoint} instance. */ public ShutdownEndpoint() { - super("/shutdown", true, false); + super("shutdown", true, false); } @Override diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/TraceEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/TraceEndpoint.java index 02e51567bb2..ef687ec3b26 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/TraceEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/TraceEndpoint.java @@ -39,7 +39,7 @@ public class TraceEndpoint extends AbstractEndpoint> { * @param repository the trace repository */ public TraceEndpoint(TraceRepository repository) { - super("/trace"); + super("trace"); Assert.notNull(repository, "Repository must not be null"); this.repository = repository; } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java index 41fe81e9082..47ecea3c001 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java @@ -32,7 +32,7 @@ import org.springframework.web.servlet.mvc.method.RequestMappingInfo; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; /** - * {@link HandlerMapping} to map {@link Endpoint}s to URLs via {@link Endpoint#getPath()}. + * {@link HandlerMapping} to map {@link Endpoint}s to URLs via {@link Endpoint#getId()}. * Only endpoints that are annotated as @FrameworkEndpoint will be mapped, * and within that class only those methods with @RequestMapping will be * exposed. The semantics of @RequestMapping should be identical to a normal diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/GenericMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/GenericMvcEndpoint.java index 6b56625f9fa..524200cbb77 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/GenericMvcEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/GenericMvcEndpoint.java @@ -40,7 +40,7 @@ public class GenericMvcEndpoint implements MvcEndpoint { @Override public String getPath() { - return this.delegate.getPath(); + return "/" + this.delegate.getId(); } @Override diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AbstractEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AbstractEndpointTests.java index f9f6fb982f1..bd6c43f75fb 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AbstractEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AbstractEndpointTests.java @@ -42,17 +42,17 @@ public abstract class AbstractEndpointTests> { private final Class type; - private final String path; + private final String id; private final boolean sensitive; private final String property; - public AbstractEndpointTests(Class configClass, Class type, String path, + public AbstractEndpointTests(Class configClass, Class type, String id, boolean sensitive, String property) { this.configClass = configClass; this.type = type; - this.path = path; + this.id = id; this.sensitive = sensitive; this.property = property; } @@ -72,8 +72,8 @@ public abstract class AbstractEndpointTests> { } @Test - public void getPath() throws Exception { - assertThat(getEndpointBean().getPath(), equalTo(this.path)); + public void getId() throws Exception { + assertThat(getEndpointBean().getId(), equalTo(this.id)); } @Test @@ -82,12 +82,12 @@ public abstract class AbstractEndpointTests> { } @Test - public void pathOverride() throws Exception { + public void idOverride() throws Exception { this.context = new AnnotationConfigApplicationContext(); - TestUtils.addEnviroment(this.context, this.property + ".path:/mypath"); + TestUtils.addEnviroment(this.context, this.property + ".id:myid"); this.context.register(this.configClass); this.context.refresh(); - assertThat(getEndpointBean().getPath(), equalTo("/mypath")); + assertThat(getEndpointBean().getId(), equalTo("myid")); } @Test diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpointTests.java index 56de89f77f8..a78e411489c 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpointTests.java @@ -42,7 +42,7 @@ public class AutoConfigurationReportEndpointTests extends AbstractEndpointTests { public AutoConfigurationReportEndpointTests() { - super(Config.class, AutoConfigurationReportEndpoint.class, "/autoconfig", true, + super(Config.class, AutoConfigurationReportEndpoint.class, "autoconfig", true, "endpoints.autoconfig"); } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/BeansEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/BeansEndpointTests.java index ab898fd64ee..eaeedde7b05 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/BeansEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/BeansEndpointTests.java @@ -35,7 +35,7 @@ import static org.junit.Assert.assertTrue; public class BeansEndpointTests extends AbstractEndpointTests { public BeansEndpointTests() { - super(Config.class, BeansEndpoint.class, "/beans", true, "endpoints.beans"); + super(Config.class, BeansEndpoint.class, "beans", true, "endpoints.beans"); } @Test diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointTests.java index 3fad25b0280..4d77d527137 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointTests.java @@ -33,7 +33,7 @@ public class ConfigurationPropertiesReportEndpointTests extends AbstractEndpointTests { public ConfigurationPropertiesReportEndpointTests() { - super(Config.class, ConfigurationPropertiesReportEndpoint.class, "/configprops", + super(Config.class, ConfigurationPropertiesReportEndpoint.class, "configprops", true, "endpoints.configprops"); } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/DumpEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/DumpEndpointTests.java index b0bbf05285e..e6a478e9eac 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/DumpEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/DumpEndpointTests.java @@ -20,7 +20,6 @@ import java.lang.management.ThreadInfo; import java.util.List; import org.junit.Test; -import org.springframework.boot.actuate.endpoint.DumpEndpoint; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -36,7 +35,7 @@ import static org.junit.Assert.assertThat; public class DumpEndpointTests extends AbstractEndpointTests { public DumpEndpointTests() { - super(Config.class, DumpEndpoint.class, "/dump", true, "endpoints.dump"); + super(Config.class, DumpEndpoint.class, "dump", true, "endpoints.dump"); } @Test diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpointTests.java index 081cf162be8..3ca7f893c4b 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/EnvironmentEndpointTests.java @@ -32,7 +32,7 @@ import static org.junit.Assert.assertThat; public class EnvironmentEndpointTests extends AbstractEndpointTests { public EnvironmentEndpointTests() { - super(Config.class, EnvironmentEndpoint.class, "/env", true, "endpoints.env"); + super(Config.class, EnvironmentEndpoint.class, "env", true, "endpoints.env"); } @Test diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/HealthEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/HealthEndpointTests.java index 05ed4853c28..e56f77380c6 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/HealthEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/HealthEndpointTests.java @@ -17,7 +17,6 @@ package org.springframework.boot.actuate.endpoint; import org.junit.Test; -import org.springframework.boot.actuate.endpoint.HealthEndpoint; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -34,7 +33,7 @@ import static org.junit.Assert.assertThat; public class HealthEndpointTests extends AbstractEndpointTests> { public HealthEndpointTests() { - super(Config.class, HealthEndpoint.class, "/health", false, "endpoints.health"); + super(Config.class, HealthEndpoint.class, "health", false, "endpoints.health"); } @Test diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InfoEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InfoEndpointTests.java index e08b53a4eb9..1bb88ec8841 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InfoEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InfoEndpointTests.java @@ -35,7 +35,7 @@ import static org.junit.Assert.assertThat; public class InfoEndpointTests extends AbstractEndpointTests { public InfoEndpointTests() { - super(Config.class, InfoEndpoint.class, "/info", false, "endpoints.info"); + super(Config.class, InfoEndpoint.class, "info", false, "endpoints.info"); } @Test diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/MetricsEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/MetricsEndpointTests.java index 76be87ac053..a05efee4319 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/MetricsEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/MetricsEndpointTests.java @@ -20,8 +20,6 @@ import java.util.Collection; import java.util.Collections; import org.junit.Test; -import org.springframework.boot.actuate.endpoint.MetricsEndpoint; -import org.springframework.boot.actuate.endpoint.PublicMetrics; import org.springframework.boot.actuate.metrics.Metric; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -38,7 +36,7 @@ import static org.junit.Assert.assertThat; public class MetricsEndpointTests extends AbstractEndpointTests { public MetricsEndpointTests() { - super(Config.class, MetricsEndpoint.class, "/metrics", true, "endpoints.metrics"); + super(Config.class, MetricsEndpoint.class, "metrics", true, "endpoints.metrics"); } @Test diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ShutdownEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ShutdownEndpointTests.java index 49bca4fcc05..da2f64f8751 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ShutdownEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ShutdownEndpointTests.java @@ -35,7 +35,7 @@ import static org.junit.Assert.assertTrue; public class ShutdownEndpointTests extends AbstractEndpointTests { public ShutdownEndpointTests() { - super(Config.class, ShutdownEndpoint.class, "/shutdown", true, + super(Config.class, ShutdownEndpoint.class, "shutdown", true, "endpoints.shutdown"); } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/TraceEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/TraceEndpointTests.java index 13e1842fb66..9d0fe89fb24 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/TraceEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/TraceEndpointTests.java @@ -19,7 +19,6 @@ package org.springframework.boot.actuate.endpoint; import java.util.Collections; import org.junit.Test; -import org.springframework.boot.actuate.endpoint.TraceEndpoint; import org.springframework.boot.actuate.trace.InMemoryTraceRepository; import org.springframework.boot.actuate.trace.Trace; import org.springframework.boot.actuate.trace.TraceRepository; @@ -38,7 +37,7 @@ import static org.junit.Assert.assertThat; public class TraceEndpointTests extends AbstractEndpointTests { public TraceEndpointTests() { - super(Config.class, TraceEndpoint.class, "/trace", true, "endpoints.trace"); + super(Config.class, TraceEndpoint.class, "trace", true, "endpoints.trace"); } @Test diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBeanExporterTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBeanExporterTests.java index 4497e3401de..1955345b6fb 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBeanExporterTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBeanExporterTests.java @@ -167,11 +167,11 @@ public class EndpointMBeanExporterTests { public static class TestEndpoint extends AbstractEndpoint { public TestEndpoint() { - super("/test"); + super("test"); } @Override - protected String doInvoke() { + public String invoke() { return "hello world"; } } From 7c78b74a761a932fa27b8a6cbc7993a7923d4769 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 18 Dec 2013 22:21:13 -0800 Subject: [PATCH 10/10] Minor polish --- .../actuate/endpoint/mvc/EndpointHandlerMapping.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java index 47ecea3c001..ed98da9aa09 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java @@ -33,18 +33,15 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl /** * {@link HandlerMapping} to map {@link Endpoint}s to URLs via {@link Endpoint#getId()}. - * Only endpoints that are annotated as @FrameworkEndpoint will be mapped, - * and within that class only those methods with @RequestMapping will be - * exposed. The semantics of @RequestMapping should be identical to a normal - * @Controller, but the endpoints should not be annotated as - * @Controller (otherwise they will be mapped by the normal MVC mechanisms). + * The semantics of {@code @RequestMapping} should be identical to a normal + * {@code @Controller}, but the endpoints should not be annotated as {@code @Controller} + * (otherwise they will be mapped by the normal MVC mechanisms). * *

* One of the aims of the mapping is to support endpoints that work as HTTP endpoints but * can still provide useful service interfaces when there is no HTTP server (and no Spring * MVC on the classpath). Note that any endpoints having method signaturess will break in * a non-servlet environment. - *

* * @author Phillip Webb * @author Christian Dupuis