Skip to content

Commit

Permalink
Reinstate support for relaxed binding for endpoint enablement
Browse files Browse the repository at this point in the history
This commit improves upon the changes made in a8bf9d3 by adding
support for relaxed binding of the endpoints.enabled and
endpoints.<name>.enabled properties. This is achieved by replacing
use of @ConditionalOnExpression (which does not support relaxed
binding) with a custom condition implementation that uses
RelaxedPropertyResolver.

Closes spring-projectsgh-2767
  • Loading branch information
wilkinsona authored and bsodzik committed May 23, 2015
1 parent 40ff5ab commit 7454c7b
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
package org.springframework.boot.actuate.autoconfigure;

import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;

import javax.servlet.Filter;
Expand Down Expand Up @@ -49,15 +53,17 @@
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
import org.springframework.boot.context.embedded.EmbeddedServletContainerException;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
Expand All @@ -66,10 +72,14 @@
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.DispatcherServlet;
Expand Down Expand Up @@ -156,14 +166,14 @@ public MvcEndpoints mvcEndpoints() {

@Bean
@ConditionalOnBean(EnvironmentEndpoint.class)
@ConditionalOnExpression("${endpoints.env.enabled:${endpoints.enabled:true}}")
@ConditionalOnEnabledEndpoint("env")
public EnvironmentMvcEndpoint environmentMvcEndpoint(EnvironmentEndpoint delegate) {
return new EnvironmentMvcEndpoint(delegate);
}

@Bean
@ConditionalOnBean(HealthEndpoint.class)
@ConditionalOnExpression("${endpoints.health.enabled:${endpoints.enabled:true}}")
@ConditionalOnEnabledEndpoint("health")
public HealthMvcEndpoint healthMvcEndpoint(HealthEndpoint delegate) {
Security security = this.managementServerProperties.getSecurity();
boolean secure = (security == null || security.isEnabled());
Expand All @@ -177,14 +187,14 @@ public HealthMvcEndpoint healthMvcEndpoint(HealthEndpoint delegate) {

@Bean
@ConditionalOnBean(MetricsEndpoint.class)
@ConditionalOnExpression("${endpoints.metrics.enabled:${endpoints.enabled:true}}")
@ConditionalOnEnabledEndpoint("metrics")
public MetricsMvcEndpoint metricsMvcEndpoint(MetricsEndpoint delegate) {
return new MetricsMvcEndpoint(delegate);
}

@Bean
@ConditionalOnBean(ShutdownEndpoint.class)
@ConditionalOnExpression("${endpoints.shutdown.enabled:false}")
@ConditionalOnEnabledEndpoint(value = "shutdown", enabledByDefault = false)
public ShutdownMvcEndpoint shutdownMvcEndpoint(ShutdownEndpoint delegate) {
return new ShutdownMvcEndpoint(delegate);
}
Expand Down Expand Up @@ -330,4 +340,77 @@ public static ManagementServerPort get(BeanFactory beanFactory) {

}

/**
* {@link Conditional} that checks whether or not an endpoint is enabled. Matches if
* the value of the {@code endpoints.<name>.enabled} property is {@code true}. Does
* not match if the property's value or {@code enabledByDefault} is {@code false}.
* Otherwise, matches if the value of the {@code endpoints.enabled} property is
* {@code true} or if the property is not configured.
*
* @since 1.2.4
*/
@Conditional(OnEnabledEndpointCondition.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public static @interface ConditionalOnEnabledEndpoint {

/**
* The name of the endpoint.
* @return The name of the endpoint
*/
public String value();

/**
* Returns whether or not the endpoint is enabled by default.
* @return {@code true} if the endpoint is enabled by default, otherwise
* {@code false}
*/
public boolean enabledByDefault() default true;

}

private static class OnEnabledEndpointCondition extends SpringBootCondition {

@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
AnnotationAttributes annotationAttributes = AnnotationAttributes
.fromMap(metadata.getAnnotationAttributes(ConditionalOnEnabledEndpoint.class
.getName()));
String endpointName = annotationAttributes.getString("value");
boolean enabledByDefault = annotationAttributes
.getBoolean("enabledByDefault");
ConditionOutcome specificEndpointOutcome = determineSpecificEndpointOutcome(
endpointName, enabledByDefault, context);
if (specificEndpointOutcome != null) {
return specificEndpointOutcome;
}
return determineAllEndpointsOutcome(context);

}

private ConditionOutcome determineSpecificEndpointOutcome(String endpointName,
boolean enabledByDefault, ConditionContext context) {
RelaxedPropertyResolver endpointPropertyResolver = new RelaxedPropertyResolver(
context.getEnvironment(), "endpoints." + endpointName + ".");
if (endpointPropertyResolver.containsProperty("enabled") || !enabledByDefault) {
boolean match = endpointPropertyResolver.getProperty("enabled",
Boolean.class, enabledByDefault);
return new ConditionOutcome(match, "The " + endpointName + " is "
+ (match ? "enabled" : "disabled"));
}
return null;
}

private ConditionOutcome determineAllEndpointsOutcome(ConditionContext context) {
RelaxedPropertyResolver allEndpointsPropertyResolver = new RelaxedPropertyResolver(
context.getEnvironment(), "endpoints.");
boolean match = Boolean.valueOf(allEndpointsPropertyResolver.getProperty(
"enabled", "true"));
return new ConditionOutcome(match, "All endpoints are "
+ (match ? "enabled" : "disabled") + " by default");
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ public void endpointsAllDisabled() throws Exception {
this.applicationContext.register(RootConfig.class, BaseConfiguration.class,
ServerPortConfig.class, EndpointWebMvcAutoConfiguration.class);
EnvironmentTestUtils.addEnvironment(this.applicationContext,
"endpoints.enabled:false");
"ENDPOINTS_ENABLED:false");
this.applicationContext.refresh();
assertThat(this.applicationContext.getBeansOfType(MvcEndpoint.class).size(),
is(equalTo(0)));
Expand Down Expand Up @@ -342,7 +342,7 @@ private void endpointEnabledOverride(String name, Class<? extends MvcEndpoint> t
ServerPortConfig.class, EndpointWebMvcAutoConfiguration.class);
EnvironmentTestUtils.addEnvironment(this.applicationContext,
"endpoints.enabled:false",
String.format("endpoints.%s.enabled:true", name));
String.format("endpoints_%s_enabled:true", name));
this.applicationContext.refresh();
assertThat(this.applicationContext.getBeansOfType(type).size(), is(equalTo(1)));
}
Expand Down

0 comments on commit 7454c7b

Please sign in to comment.