From 617c97322d8d0c6d4e8081bd5d4a4f8e2d8eb565 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 22 Feb 2016 17:55:27 +0000 Subject: [PATCH] Allow endpoint paths to be configured via endpoint..path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support for configuring an endpoint’s path separately from its id was introduced in 97255785, but it didn’t work for a variety of reasons: 1. Some custom MVC endpoints did not have configuration properties bound to them 2. Some generic endpoints rejected the path property as they were configured not to ignore unknown fields 3. The property used to configure the path was dependent on the id of the endpoint. This meant that the path property’s name would change if the endpoint’s id was changed This commit addresses these problems: 1. @ConfigurationProperties has been added to custom MvcEndpoints where it was missing 2. Generic endpoints have been updated to ignore unknown fields, allowing the path of their MVC adapter to be configured 3. Rather than using the id of a generic endpoint to determine the name of its path property, the prefix or value of the endpoint’s @ConfigurationProperties annotation is used instead. Any generic endpoint that is not annotated with @ConfigurationProperties is ignored, making its path unconfigurable. Closes gh-5105 --- .../AutoConfigurationReportEndpoint.java | 4 +- .../boot/actuate/endpoint/BeansEndpoint.java | 4 +- ...ConfigurationPropertiesReportEndpoint.java | 4 +- .../boot/actuate/endpoint/DumpEndpoint.java | 4 +- .../actuate/endpoint/EnvironmentEndpoint.java | 4 +- .../boot/actuate/endpoint/FlywayEndpoint.java | 4 +- .../boot/actuate/endpoint/HealthEndpoint.java | 4 +- .../boot/actuate/endpoint/InfoEndpoint.java | 4 +- .../actuate/endpoint/LiquibaseEndpoint.java | 4 +- .../endpoint/RequestMappingEndpoint.java | 2 +- .../actuate/endpoint/ShutdownEndpoint.java | 4 +- .../boot/actuate/endpoint/TraceEndpoint.java | 4 +- .../mvc/AbstractEndpointMvcAdapter.java | 5 +- .../actuate/endpoint/mvc/DocsMvcEndpoint.java | 5 +- .../endpoint/mvc/EnvironmentMvcEndpoint.java | 4 +- .../endpoint/mvc/HalJsonMvcEndpoint.java | 2 +- .../endpoint/mvc/HealthMvcEndpoint.java | 4 +- .../endpoint/mvc/JolokiaMvcEndpoint.java | 6 +- .../endpoint/mvc/LogFileMvcEndpoint.java | 4 +- .../endpoint/mvc/MetricsMvcEndpoint.java | 4 +- .../actuate/endpoint/mvc/MvcEndpoints.java | 21 ++- .../endpoint/mvc/ShutdownMvcEndpoint.java | 4 +- ...itional-spring-configuration-metadata.json | 35 ++++ .../MvcEndpointPathConfigurationTests.java | 173 ++++++++++++++++++ .../endpoint/mvc/MvcEndpointsTests.java | 2 + 25 files changed, 277 insertions(+), 38 deletions(-) create mode 100644 spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MvcEndpointPathConfigurationTests.java 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 6bdfc2af31..ad4239a10b 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,7 +44,7 @@ import org.springframework.util.StringUtils; * @author Dave Syer * @author Andy Wilkinson */ -@ConfigurationProperties(prefix = "endpoints.autoconfig", ignoreUnknownFields = false) +@ConfigurationProperties(prefix = "endpoints.autoconfig") public class AutoConfigurationReportEndpoint extends AbstractEndpoint { @Autowired 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 03c0615035..af5fd95d91 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2016 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. @@ -35,7 +35,7 @@ import org.springframework.core.env.Environment; * * @author Dave Syer */ -@ConfigurationProperties(prefix = "endpoints.beans", ignoreUnknownFields = false) +@ConfigurationProperties(prefix = "endpoints.beans") public class BeansEndpoint extends AbstractEndpoint> implements ApplicationContextAware { 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 a12c347eef..ec32d41f3b 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,7 +58,7 @@ import org.springframework.util.StringUtils; * @author Christian Dupuis * @author Dave Syer */ -@ConfigurationProperties(prefix = "endpoints.configprops", ignoreUnknownFields = false) +@ConfigurationProperties(prefix = "endpoints.configprops") public class ConfigurationPropertiesReportEndpoint extends AbstractEndpoint> implements ApplicationContextAware { 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 ce34dae2f3..423b4921e1 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2016 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. @@ -28,7 +28,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * * @author Dave Syer */ -@ConfigurationProperties(prefix = "endpoints.dump", ignoreUnknownFields = false) +@ConfigurationProperties(prefix = "endpoints.dump") public class DumpEndpoint extends AbstractEndpoint> { /** 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 ed45809a77..44ef33b05f 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,7 +36,7 @@ import org.springframework.core.env.StandardEnvironment; * @author Phillip Webb * @author Christian Dupuis */ -@ConfigurationProperties(prefix = "endpoints.env", ignoreUnknownFields = false) +@ConfigurationProperties(prefix = "endpoints.env") public class EnvironmentEndpoint extends AbstractEndpoint> { private final Sanitizer sanitizer = new Sanitizer(); diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/FlywayEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/FlywayEndpoint.java index 282a052629..3befb1154d 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/FlywayEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/FlywayEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,7 +36,7 @@ import org.springframework.util.Assert; * @author Phillip Webb * @since 1.3.0 */ -@ConfigurationProperties(prefix = "endpoints.flyway", ignoreUnknownFields = true) +@ConfigurationProperties(prefix = "endpoints.flyway") public class FlywayEndpoint extends AbstractEndpoint> { private final Flyway flyway; 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 7e171bab68..e90c71ff71 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 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. @@ -32,7 +32,7 @@ import org.springframework.util.Assert; * @author Christian Dupuis * @author Andy Wilkinson */ -@ConfigurationProperties(prefix = "endpoints.health", ignoreUnknownFields = true) +@ConfigurationProperties(prefix = "endpoints.health") public class HealthEndpoint extends AbstractEndpoint { private final HealthIndicator healthIndicator; 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 42a20c595e..af8396901c 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2016 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. @@ -28,7 +28,7 @@ import org.springframework.util.Assert; * * @author Dave Syer */ -@ConfigurationProperties(prefix = "endpoints.info", ignoreUnknownFields = false) +@ConfigurationProperties(prefix = "endpoints.info") public class InfoEndpoint extends AbstractEndpoint> { private final Map info; diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/LiquibaseEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/LiquibaseEndpoint.java index d96a99973a..796beb373e 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/LiquibaseEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/LiquibaseEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,7 +36,7 @@ import org.springframework.util.Assert; * @author Eddú Meléndez * @since 1.3.0 */ -@ConfigurationProperties(prefix = "endpoints.liquibase", ignoreUnknownFields = true) +@ConfigurationProperties(prefix = "endpoints.liquibase") public class LiquibaseEndpoint extends AbstractEndpoint>> { private final SpringLiquibase liquibase; diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpoint.java index a27701e259..647db74461 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpoint.java @@ -38,7 +38,7 @@ import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping; * @author Dave Syer * @author Andy Wilkinson */ -@ConfigurationProperties(prefix = "endpoints.mappings", ignoreUnknownFields = false) +@ConfigurationProperties(prefix = "endpoints.mappings") public class RequestMappingEndpoint extends AbstractEndpoint> implements ApplicationContextAware { 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 6de9ca8d64..2b78563cf5 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2016 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. @@ -31,7 +31,7 @@ import org.springframework.context.ConfigurableApplicationContext; * @author Dave Syer * @author Christian Dupuis */ -@ConfigurationProperties(prefix = "endpoints.shutdown", ignoreUnknownFields = false) +@ConfigurationProperties(prefix = "endpoints.shutdown") public class ShutdownEndpoint extends AbstractEndpoint> implements ApplicationContextAware { 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 1c4899b63e..86d2c830e2 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2016 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. @@ -28,7 +28,7 @@ import org.springframework.util.Assert; * * @author Dave Syer */ -@ConfigurationProperties(prefix = "endpoints.trace", ignoreUnknownFields = false) +@ConfigurationProperties(prefix = "endpoints.trace") public class TraceEndpoint extends AbstractEndpoint> { private final TraceRepository repository; diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractEndpointMvcAdapter.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractEndpointMvcAdapter.java index 9cef437865..a90587d58f 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractEndpointMvcAdapter.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractEndpointMvcAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 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. @@ -34,6 +34,9 @@ public abstract class AbstractEndpointMvcAdapter> private final E delegate; + /** + * Endpoint URL path. + */ private String path; /** diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/DocsMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/DocsMvcEndpoint.java index ff4d463940..3873ff1b52 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/DocsMvcEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/DocsMvcEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,6 +40,9 @@ public class DocsMvcEndpoint extends WebMvcConfigurerAdapter private Environment environment; + /** + * Endpoint URL path. + */ private String path = "/docs"; /** 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 0e4de59cf7..6de5236f34 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 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. @@ -17,6 +17,7 @@ package org.springframework.boot.actuate.endpoint.mvc; import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint; +import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.EnvironmentAware; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.EnumerablePropertySource; @@ -38,6 +39,7 @@ import org.springframework.web.bind.annotation.ResponseStatus; * @author Christian Dupuis * @author Andy Wilkinson */ +@ConfigurationProperties(prefix = "endpoints.env") public class EnvironmentMvcEndpoint extends EndpointMvcAdapter implements EnvironmentAware { diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HalJsonMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HalJsonMvcEndpoint.java index c0c32516ad..8f36f366db 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HalJsonMvcEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HalJsonMvcEndpoint.java @@ -49,7 +49,7 @@ public class HalJsonMvcEndpoint extends WebMvcConfigurerAdapter * Endpoint URL path. */ @NotNull - @Pattern(regexp = "^$|/[^/]*", message = "Path must be empty or start with /") + @Pattern(regexp = "^$|/.*", message = "Path must be empty or start with /") private String path; /** diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HealthMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HealthMvcEndpoint.java index 51dc346060..5167f6f798 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HealthMvcEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HealthMvcEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 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. @@ -25,6 +25,7 @@ import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.Status; import org.springframework.boot.bind.RelaxedNames; import org.springframework.boot.bind.RelaxedPropertyResolver; +import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.EnvironmentAware; import org.springframework.core.env.Environment; import org.springframework.http.HttpStatus; @@ -46,6 +47,7 @@ import org.springframework.web.bind.annotation.ResponseBody; * @author Phillip Webb * @since 1.1.0 */ +@ConfigurationProperties(prefix = "endpoints.health") public class HealthMvcEndpoint extends AbstractEndpointMvcAdapter implements EnvironmentAware { diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpoint.java index 180387d9fd..d2879d6628 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/JolokiaMvcEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2016 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. @@ -59,8 +59,8 @@ public class JolokiaMvcEndpoint implements MvcEndpoint, InitializingBean, * Endpoint URL path. */ @NotNull - @Pattern(regexp = "/[^?#]*", message = "Path must start with /") - private String path = "/jolokia";; + @Pattern(regexp = "/.*", message = "Path must start with /") + private String path = "/jolokia"; /** * Enable the endpoint. diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/LogFileMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/LogFileMvcEndpoint.java index e2b36b7d92..59780dfe7d 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/LogFileMvcEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/LogFileMvcEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 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. @@ -59,7 +59,7 @@ public class LogFileMvcEndpoint implements MvcEndpoint, EnvironmentAware { * Endpoint URL path. */ @NotNull - @Pattern(regexp = "/[^/]*", message = "Path must start with /") + @Pattern(regexp = "/.*", message = "Path must start with /") private String path = "/logfile"; /** 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 57dbc43493..ea87cffb85 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 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. @@ -19,6 +19,7 @@ package org.springframework.boot.actuate.endpoint.mvc; import java.util.Map; import org.springframework.boot.actuate.endpoint.MetricsEndpoint; +import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.PathVariable; @@ -34,6 +35,7 @@ import org.springframework.web.bind.annotation.ResponseStatus; * @author Andy Wilkinson * @author Sergei Egorov */ +@ConfigurationProperties(prefix = "endpoints.metrics") public class MetricsMvcEndpoint extends EndpointMvcAdapter { private final MetricsEndpoint delegate; 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 index de0e9fa0bf..05acf91058 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2016 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. @@ -24,9 +24,13 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.InitializingBean; import org.springframework.boot.actuate.endpoint.Endpoint; +import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; /** * A registry for all {@link MvcEndpoint} beans, and a factory for a set of generic ones @@ -64,8 +68,8 @@ public class MvcEndpoints implements ApplicationContextAware, InitializingBean { for (Endpoint endpoint : delegates) { if (isGenericEndpoint(endpoint.getClass()) && endpoint.isEnabled()) { EndpointMvcAdapter adapter = new EndpointMvcAdapter(endpoint); - String path = this.applicationContext.getEnvironment() - .getProperty("endpoints." + endpoint.getId() + ".path"); + String path = determinePath(endpoint, + this.applicationContext.getEnvironment()); if (path != null) { adapter.setPath(path); } @@ -94,4 +98,15 @@ public class MvcEndpoints implements ApplicationContextAware, InitializingBean { && !MvcEndpoint.class.isAssignableFrom(type); } + private String determinePath(Endpoint endpoint, Environment environment) { + ConfigurationProperties configurationProperties = AnnotationUtils + .findAnnotation(endpoint.getClass(), ConfigurationProperties.class); + if (configurationProperties != null) { + String prefix = StringUtils.hasText(configurationProperties.prefix()) + ? configurationProperties.prefix() : configurationProperties.value(); + return environment.getProperty(prefix + ".path"); + } + return null; + } + } 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 c38098f559..2d044c784d 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2016 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. @@ -20,6 +20,7 @@ import java.util.Collections; import java.util.Map; import org.springframework.boot.actuate.endpoint.ShutdownEndpoint; +import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; @@ -31,6 +32,7 @@ import org.springframework.web.bind.annotation.ResponseBody; * * @author Dave Syer */ +@ConfigurationProperties(prefix = "endpoints.shutdown") public class ShutdownMvcEndpoint extends EndpointMvcAdapter { public ShutdownMvcEndpoint(ShutdownEndpoint delegate) { diff --git a/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 1fc164cfed..15d38abf94 100644 --- a/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,28 +1,63 @@ {"properties": [ + { + "name": "endpoints.autoconfig.path", + "type": "java.lang.String", + "description": "Endpoint URL path." + }, + { + "name": "endpoints.beans.path", + "type": "java.lang.String", + "description": "Endpoint URL path." + }, { "name": "endpoints.configprops.keys-to-sanitize", "type": "java.lang.String[]", "sourceType": "org.springframework.boot.actuate.endpoint.ConfigurationPropertiesReportEndpoint", "description": "Keys that should be sanitized. Keys can be simple strings that the property ends with or regex expressions." }, + { + "name": "endpoints.configprops.path", + "type": "java.lang.String", + "description": "Endpoint URL path." + }, + { + "name": "endpoints.dump.path", + "type": "java.lang.String", + "description": "Endpoint URL path." + }, { "name": "endpoints.env.keys-to-sanitize", "type": "java.lang.String[]", "sourceType": "org.springframework.boot.actuate.endpoint.EnvironmentEndpoint", "description": "Keys that should be sanitized. Keys can be simple strings that the property ends with or regex expressions." }, + { + "name": "endpoints.info.path", + "type": "java.lang.String", + "description": "Endpoint URL path." + }, { "name": "endpoints.jmx.enabled", "type": "java.lang.Boolean", "description": "Enable JMX export of all endpoints.", "defaultValue": true }, + { + "name": "endpoints.mappings.path", + "type": "java.lang.String", + "description": "Endpoint URL path." + }, { "name": "endpoints.metrics.filter.enabled", "type": "java.lang.Boolean", "description": "Enable the metrics servlet filter.", "defaultValue": true }, + { + "name": "endpoints.trace.path", + "type": "java.lang.String", + "description": "Endpoint URL path." + }, { "name": "info", "type": "java.util.Map", diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MvcEndpointPathConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MvcEndpointPathConfigurationTests.java new file mode 100644 index 0000000000..5ff498dadb --- /dev/null +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MvcEndpointPathConfigurationTests.java @@ -0,0 +1,173 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.autoconfigure; + +import liquibase.integration.spring.SpringLiquibase; +import org.flywaydb.core.Flyway; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.boot.actuate.endpoint.AutoConfigurationReportEndpoint; +import org.springframework.boot.actuate.endpoint.BeansEndpoint; +import org.springframework.boot.actuate.endpoint.ConfigurationPropertiesReportEndpoint; +import org.springframework.boot.actuate.endpoint.DumpEndpoint; +import org.springframework.boot.actuate.endpoint.FlywayEndpoint; +import org.springframework.boot.actuate.endpoint.InfoEndpoint; +import org.springframework.boot.actuate.endpoint.LiquibaseEndpoint; +import org.springframework.boot.actuate.endpoint.RequestMappingEndpoint; +import org.springframework.boot.actuate.endpoint.ShutdownEndpoint; +import org.springframework.boot.actuate.endpoint.TraceEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.DocsMvcEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter; +import org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.HalJsonMvcEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.JolokiaMvcEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.LogFileMvcEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.ManagementServletContext; +import org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint; +import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoints; +import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport; +import org.springframework.boot.autoconfigure.test.ImportAutoConfiguration; +import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration; +import org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration; +import org.springframework.boot.test.EnvironmentTestUtils; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +/** + * Tests for configuring the path of an MVC endpoint. + * + * @author Andy Wilkinson + */ +@RunWith(Parameterized.class) +public class MvcEndpointPathConfigurationTests { + + private final String endpointName; + + private final Class endpointClass; + + private AnnotationConfigWebApplicationContext context; + + @After + public void cleanUp() { + if (this.context != null) { + this.context.close(); + } + } + + @Parameters(name = "{0}") + public static Object[] parameters() { + return new Object[] { new Object[] { "actuator", HalJsonMvcEndpoint.class }, + new Object[] { "autoconfig", AutoConfigurationReportEndpoint.class }, + new Object[] { "beans", BeansEndpoint.class }, + new Object[] { "configprops", + ConfigurationPropertiesReportEndpoint.class }, + new Object[] { "docs", DocsMvcEndpoint.class }, + new Object[] { "dump", DumpEndpoint.class }, + new Object[] { "env", EnvironmentMvcEndpoint.class }, + new Object[] { "flyway", FlywayEndpoint.class }, + new Object[] { "health", HealthMvcEndpoint.class }, + new Object[] { "info", InfoEndpoint.class }, + new Object[] { "jolokia", JolokiaMvcEndpoint.class }, + new Object[] { "liquibase", LiquibaseEndpoint.class }, + new Object[] { "logfile", LogFileMvcEndpoint.class }, + new Object[] { "mappings", RequestMappingEndpoint.class }, + new Object[] { "metrics", MetricsMvcEndpoint.class }, + new Object[] { "shutdown", ShutdownEndpoint.class }, + new Object[] { "trace", TraceEndpoint.class } }; + } + + public MvcEndpointPathConfigurationTests(String endpointName, + Class endpointClass) { + this.endpointName = endpointName; + this.endpointClass = endpointClass; + } + + @Test + public void pathCanBeConfigured() { + this.context = new AnnotationConfigWebApplicationContext(); + this.context.register(TestConfiguration.class); + this.context.setServletContext(new MockServletContext()); + EnvironmentTestUtils.addEnvironment(this.context, + "endpoints." + this.endpointName + ".path" + ":/custom/path", + "endpoints." + this.endpointName + ".enabled:true", + "logging.file:target/test.log"); + this.context.refresh(); + assertThat(getConfiguredPath(), is(equalTo("/custom/path"))); + } + + private String getConfiguredPath() { + if (MvcEndpoint.class.isAssignableFrom(this.endpointClass)) { + return ((MvcEndpoint) this.context.getBean(this.endpointClass)).getPath(); + } + for (MvcEndpoint endpoint : this.context.getBean(MvcEndpoints.class) + .getEndpoints()) { + if (endpoint instanceof EndpointMvcAdapter && this.endpointClass + .isInstance(((EndpointMvcAdapter) endpoint).getDelegate())) { + return ((EndpointMvcAdapter) endpoint).getPath(); + } + } + throw new IllegalStateException( + "Could not get configured path for " + this.endpointClass); + } + + @Configuration + @ImportAutoConfiguration({ EndpointAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + ManagementServerPropertiesAutoConfiguration.class, + ServerPropertiesAutoConfiguration.class, + EndpointWebMvcAutoConfiguration.class, JolokiaAutoConfiguration.class, + EndpointAutoConfiguration.class }) + + protected static class TestConfiguration { + + @Bean + public ConditionEvaluationReport conditionEvaluationReport( + ConfigurableListableBeanFactory beanFactory) { + return ConditionEvaluationReport.get(beanFactory); + } + + @Bean + public FlywayEndpoint flyway() { + return new FlywayEndpoint(new Flyway()); + } + + @Bean + public LiquibaseEndpoint liquibase() { + return new LiquibaseEndpoint(new SpringLiquibase()); + } + + @Bean + public DocsMvcEndpoint docs(ManagementServletContext managementServletContext) { + return new DocsMvcEndpoint(managementServletContext); + } + + } + +} diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpointsTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpointsTests.java index 6b1efe420e..233b5bf286 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpointsTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpointsTests.java @@ -19,6 +19,7 @@ package org.springframework.boot.actuate.endpoint.mvc; import org.junit.Test; import org.springframework.boot.actuate.endpoint.AbstractEndpoint; +import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.context.support.StaticApplicationContext; @@ -77,6 +78,7 @@ public class MvcEndpointsTests { this.endpoints.getEndpoints().iterator().next().getPath()); } + @ConfigurationProperties("endpoints.test") protected static class TestEndpoint extends AbstractEndpoint { public TestEndpoint() {