Commit fd5c43cd authored by Phillip Webb's avatar Phillip Webb

Separate endpoint concerns

Update endpoint code to provide cleaner separation of concerns.
Specifically, the top level endpoint package is no longer aware of
the fact that JMX and HTTP are ultimately used to expose endpoints.
Caching concerns have also been abstracted behind a general purpose
`OperationMethodInvokerAdvisor` interface.

Configuration properties have been refined to further enforce
separation. The `management.endpoint.<name>` prefix provides
configuration for a  single endpoint (including enable and cache
time-to-live). These  properties are now technology agnostic (they
don't include `web` or `jmx` sub properties).

The `management.endpoints.<technology>` prefix provide exposure specific
configuration. For example, `management.endpoints.web.path-mapping`
allow endpoint URLs to be changed.

Endpoint enabled/disabled logic has been simplified so that endpoints
can't be disabled per exposure technology. Instead a filter based
approach is used to allow refinement of what endpoints are exposed over
a given technology.

Fixes gh-10176
parent d24709c6
......@@ -18,8 +18,8 @@ package org.springframework.boot.actuate.autoconfigure.audit;
import org.springframework.boot.actuate.audit.AuditEventRepository;
import org.springframework.boot.actuate.audit.AuditEventsEndpoint;
import org.springframework.boot.actuate.audit.AuditEventsEndpointWebExtension;
import org.springframework.boot.actuate.audit.AuditEventsJmxEndpointExtension;
import org.springframework.boot.actuate.audit.AuditEventsWebEndpointExtension;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
import org.springframework.boot.actuate.logging.LoggersEndpoint;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
......@@ -63,9 +63,9 @@ public class AuditEventsEndpointAutoConfiguration {
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
@ConditionalOnBean(AuditEventsEndpoint.class)
public AuditEventsWebEndpointExtension auditEventsWebEndpointExtension(
public AuditEventsEndpointWebExtension auditEventsWebEndpointExtension(
AuditEventsEndpoint auditEventsEndpoint) {
return new AuditEventsWebEndpointExtension(auditEventsEndpoint);
return new AuditEventsEndpointWebExtension(auditEventsEndpoint);
}
}
......@@ -32,13 +32,13 @@ import org.springframework.boot.actuate.autoconfigure.cloudfoundry.SecurityRespo
import org.springframework.boot.actuate.endpoint.EndpointInfo;
import org.springframework.boot.actuate.endpoint.OperationInvoker;
import org.springframework.boot.actuate.endpoint.OperationType;
import org.springframework.boot.actuate.endpoint.ParameterMappingException;
import org.springframework.boot.actuate.endpoint.ParametersMissingException;
import org.springframework.boot.actuate.endpoint.reflect.ParameterMappingException;
import org.springframework.boot.actuate.endpoint.reflect.ParametersMissingException;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.Link;
import org.springframework.boot.actuate.endpoint.web.WebEndpointOperation;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.endpoint.web.WebOperation;
import org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping;
import org.springframework.boot.endpoint.web.EndpointMapping;
import org.springframework.http.HttpMethod;
......@@ -81,7 +81,7 @@ class CloudFoundryWebFluxEndpointHandlerMapping
}
@Override
protected void registerMappingForOperation(WebEndpointOperation operation) {
protected void registerMappingForOperation(WebOperation operation) {
OperationType operationType = operation.getType();
OperationInvoker operationInvoker = operation.getInvoker();
if (operation.isBlocking()) {
......@@ -135,7 +135,7 @@ class CloudFoundryWebFluxEndpointHandlerMapping
* @param securityInterceptor the Security Interceptor
*/
CloudFoundryWebFluxEndpointHandlerMapping(EndpointMapping endpointMapping,
Collection<EndpointInfo<WebEndpointOperation>> webEndpoints,
Collection<EndpointInfo<WebOperation>> webEndpoints,
EndpointMediaTypes endpointMediaTypes, CorsConfiguration corsConfiguration,
ReactiveCloudFoundrySecurityInterceptor securityInterceptor) {
super(endpointMapping, webEndpoints, endpointMediaTypes, corsConfiguration);
......
......@@ -21,10 +21,9 @@ import java.util.Collections;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.actuate.autoconfigure.endpoint.DefaultCachingConfigurationFactory;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.endpoint.ParameterMapper;
import org.springframework.boot.actuate.endpoint.reflect.ParameterMapper;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.EndpointPathResolver;
import org.springframework.boot.actuate.endpoint.web.annotation.WebAnnotationEndpointDiscoverer;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
......@@ -68,17 +67,16 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration {
@Bean
public CloudFoundryWebFluxEndpointHandlerMapping cloudFoundryWebFluxEndpointHandlerMapping(
ParameterMapper parameterMapper, EndpointMediaTypes endpointMediaTypes,
WebClient.Builder webClientBuilder, Environment environment,
DefaultCachingConfigurationFactory cachingConfigurationFactory,
WebEndpointProperties webEndpointProperties) {
WebClient.Builder webClientBuilder) {
WebAnnotationEndpointDiscoverer endpointDiscoverer = new WebAnnotationEndpointDiscoverer(
this.applicationContext, parameterMapper, cachingConfigurationFactory,
endpointMediaTypes, (id) -> id);
this.applicationContext, parameterMapper, endpointMediaTypes,
EndpointPathResolver.useEndpointId(), null, null);
ReactiveCloudFoundrySecurityInterceptor securityInterceptor = getSecurityInterceptor(
webClientBuilder, this.applicationContext.getEnvironment());
return new CloudFoundryWebFluxEndpointHandlerMapping(
new EndpointMapping("/cloudfoundryapplication"),
endpointDiscoverer.discoverEndpoints(), endpointMediaTypes,
getCorsConfiguration(),
getSecurityInterceptor(webClientBuilder, environment));
getCorsConfiguration(), securityInterceptor);
}
private ReactiveCloudFoundrySecurityInterceptor getSecurityInterceptor(
......
......@@ -18,9 +18,8 @@ package org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet;
import java.util.Arrays;
import org.springframework.boot.actuate.autoconfigure.endpoint.DefaultCachingConfigurationFactory;
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
import org.springframework.boot.actuate.endpoint.ParameterMapper;
import org.springframework.boot.actuate.endpoint.reflect.ParameterMapper;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.EndpointPathResolver;
import org.springframework.boot.actuate.endpoint.web.annotation.WebAnnotationEndpointDiscoverer;
......@@ -71,17 +70,17 @@ public class CloudFoundryActuatorAutoConfiguration {
@Bean
public CloudFoundryWebEndpointServletHandlerMapping cloudFoundryWebEndpointServletHandlerMapping(
ParameterMapper parameterMapper,
DefaultCachingConfigurationFactory cachingConfigurationFactory,
EndpointMediaTypes endpointMediaTypes, Environment environment,
RestTemplateBuilder builder) {
ParameterMapper parameterMapper, EndpointMediaTypes endpointMediaTypes,
RestTemplateBuilder restTemplateBuilder) {
WebAnnotationEndpointDiscoverer endpointDiscoverer = new WebAnnotationEndpointDiscoverer(
this.applicationContext, parameterMapper, cachingConfigurationFactory,
endpointMediaTypes, EndpointPathResolver.useEndpointId());
this.applicationContext, parameterMapper, endpointMediaTypes,
EndpointPathResolver.useEndpointId(), null, null);
CloudFoundrySecurityInterceptor securityInterceptor = getSecurityInterceptor(
restTemplateBuilder, this.applicationContext.getEnvironment());
return new CloudFoundryWebEndpointServletHandlerMapping(
new EndpointMapping("/cloudfoundryapplication"),
endpointDiscoverer.discoverEndpoints(), endpointMediaTypes,
getCorsConfiguration(), getSecurityInterceptor(builder, environment));
getCorsConfiguration(), securityInterceptor);
}
private CloudFoundrySecurityInterceptor getSecurityInterceptor(
......
......@@ -35,13 +35,13 @@ import org.springframework.boot.actuate.autoconfigure.cloudfoundry.AccessLevel;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.SecurityResponse;
import org.springframework.boot.actuate.endpoint.EndpointInfo;
import org.springframework.boot.actuate.endpoint.OperationInvoker;
import org.springframework.boot.actuate.endpoint.ParameterMappingException;
import org.springframework.boot.actuate.endpoint.ParametersMissingException;
import org.springframework.boot.actuate.endpoint.reflect.ParameterMappingException;
import org.springframework.boot.actuate.endpoint.reflect.ParametersMissingException;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.Link;
import org.springframework.boot.actuate.endpoint.web.WebEndpointOperation;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.endpoint.web.WebOperation;
import org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping;
import org.springframework.boot.endpoint.web.EndpointMapping;
import org.springframework.http.HttpMethod;
......@@ -78,7 +78,7 @@ class CloudFoundryWebEndpointServletHandlerMapping
private final EndpointLinksResolver endpointLinksResolver = new EndpointLinksResolver();
CloudFoundryWebEndpointServletHandlerMapping(EndpointMapping endpointMapping,
Collection<EndpointInfo<WebEndpointOperation>> webEndpoints,
Collection<EndpointInfo<WebOperation>> webEndpoints,
EndpointMediaTypes endpointMediaTypes, CorsConfiguration corsConfiguration,
CloudFoundrySecurityInterceptor securityInterceptor) {
super(endpointMapping, webEndpoints, endpointMediaTypes, corsConfiguration);
......@@ -125,7 +125,7 @@ class CloudFoundryWebEndpointServletHandlerMapping
}
@Override
protected void registerMappingForOperation(WebEndpointOperation operation) {
protected void registerMappingForOperation(WebOperation operation) {
registerMapping(createRequestMappingInfo(operation),
new OperationHandler(operation.getInvoker(), operation.getId(),
this.securityInterceptor),
......
......@@ -25,7 +25,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
* @author Stephane Nicoll
* @since 2.0.0
*/
@ConfigurationProperties("endpoints.configprops")
@ConfigurationProperties("management.endpoint.configprops")
public class ConfigurationPropertiesReportEndpointProperties {
/**
......
......@@ -16,23 +16,12 @@
package org.springframework.boot.actuate.autoconfigure.endpoint;
import java.util.Arrays;
import java.util.List;
import org.springframework.boot.actuate.endpoint.EndpointExposure;
import org.springframework.boot.actuate.endpoint.ParameterMapper;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.cache.CachingConfigurationFactory;
import org.springframework.boot.actuate.endpoint.cache.CachingOperationInvokerAdvisor;
import org.springframework.boot.actuate.endpoint.convert.ConversionServiceParameterMapper;
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.EndpointPathResolver;
import org.springframework.boot.actuate.endpoint.web.WebEndpointOperation;
import org.springframework.boot.actuate.endpoint.web.annotation.WebAnnotationEndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.reflect.ParameterMapper;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
......@@ -54,49 +43,11 @@ public class EndpointAutoConfiguration {
}
@Bean
@ConditionalOnMissingBean(CachingConfigurationFactory.class)
public DefaultCachingConfigurationFactory endpointCacheConfigurationFactory(
@ConditionalOnMissingBean
public CachingOperationInvokerAdvisor endpointCachingOperationInvokerAdvisor(
Environment environment) {
return new DefaultCachingConfigurationFactory(environment);
}
@Configuration
@ConditionalOnWebApplication
static class EndpointWebConfiguration {
private static final List<String> MEDIA_TYPES = Arrays
.asList(ActuatorMediaType.V2_JSON, "application/json");
private final ApplicationContext applicationContext;
EndpointWebConfiguration(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Bean
public EndpointMediaTypes endpointMediaTypes() {
return new EndpointMediaTypes(MEDIA_TYPES, MEDIA_TYPES);
}
@Bean
@ConditionalOnMissingBean
public EndpointPathResolver endpointPathResolver(Environment environment) {
return new DefaultEndpointPathResolver(environment);
}
@Bean
public EndpointProvider<WebEndpointOperation> webEndpointProvider(
ParameterMapper parameterMapper,
DefaultCachingConfigurationFactory cachingConfigurationFactory,
EndpointPathResolver endpointPathResolver) {
Environment environment = this.applicationContext.getEnvironment();
WebAnnotationEndpointDiscoverer endpointDiscoverer = new WebAnnotationEndpointDiscoverer(
this.applicationContext, parameterMapper, cachingConfigurationFactory,
endpointMediaTypes(), endpointPathResolver);
return new EndpointProvider<>(environment, endpointDiscoverer,
EndpointExposure.WEB);
}
return new CachingOperationInvokerAdvisor(
new EndpointIdTimeToLivePropertyFunction(environment));
}
}
/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.endpoint;
import org.springframework.boot.actuate.endpoint.DefaultEnablement;
import org.springframework.boot.actuate.endpoint.EndpointExposure;
import org.springframework.core.env.Environment;
import org.springframework.util.Assert;
/**
* Determines an endpoint's enablement based on the current {@link Environment}.
*
* @author Stephane Nicoll
* @since 2.0.0
*/
public class EndpointEnablementProvider {
private final Environment environment;
/**
* Creates a new instance with the {@link Environment} to use.
* @param environment the environment
*/
public EndpointEnablementProvider(Environment environment) {
this.environment = environment;
}
/**
* Return the {@link EndpointEnablement} of an endpoint with no specific tech
* exposure.
* @param endpointId the id of the endpoint
* @param defaultEnablement the {@link DefaultEnablement} of the endpoint
* @return the {@link EndpointEnablement} of that endpoint
*/
public EndpointEnablement getEndpointEnablement(String endpointId,
DefaultEnablement defaultEnablement) {
return getEndpointEnablement(endpointId, defaultEnablement, null);
}
/**
* Return the {@link EndpointEnablement} of an endpoint for a specific tech exposure.
* @param endpointId the id of the endpoint
* @param defaultEnablement the {@link DefaultEnablement} of the endpoint
* @param exposure the requested {@link EndpointExposure}
* @return the {@link EndpointEnablement} of that endpoint for the specified
* {@link EndpointExposure}
*/
public EndpointEnablement getEndpointEnablement(String endpointId,
DefaultEnablement defaultEnablement, EndpointExposure exposure) {
Assert.hasText(endpointId, "Endpoint id must have a value");
Assert.isTrue(!endpointId.equals("default"),
"Endpoint id 'default' is a reserved "
+ "value and cannot be used by an endpoint");
EndpointEnablement result = findEnablement(endpointId, exposure);
if (result != null) {
return result;
}
result = findEnablement(getKey(endpointId, "enabled"));
if (result != null) {
return result;
}
// All endpoints specific attributes have been looked at. Checking default value
// for the endpoint
if (defaultEnablement != DefaultEnablement.NEUTRAL) {
return getDefaultEndpointEnablement(endpointId,
(defaultEnablement == DefaultEnablement.ENABLED), exposure);
}
return getGlobalEndpointEnablement(endpointId, defaultEnablement, exposure);
}
private EndpointEnablement findEnablement(String endpointId,
EndpointExposure exposure) {
if (exposure != null) {
return findEnablement(getKey(endpointId, exposure));
}
return findEnablementForAnyExposureTechnology(endpointId);
}
private EndpointEnablement getGlobalEndpointEnablement(String endpointId,
DefaultEnablement defaultEnablement, EndpointExposure exposure) {
EndpointEnablement result = findGlobalEndpointEnablement(exposure);
if (result != null) {
return result;
}
result = findEnablement(getKey("default", "enabled"));
if (result != null) {
return result;
}
boolean enablement = determineGlobalDefaultEnablement(defaultEnablement,
exposure);
String message = determineGlobalDefaultMessage(endpointId, enablement, exposure,
defaultEnablement);
return new EndpointEnablement(enablement, message);
}
private boolean determineGlobalDefaultEnablement(DefaultEnablement defaultEnablement,
EndpointExposure exposure) {
if (defaultEnablement == DefaultEnablement.NEUTRAL) {
return exposure == null || exposure.isEnabledByDefault();
}
return (defaultEnablement == DefaultEnablement.ENABLED);
}
private String determineGlobalDefaultMessage(String endpointId, boolean enablement,
EndpointExposure exposure, DefaultEnablement defaultEnablement) {
StringBuilder message = new StringBuilder();
message.append(String.format("endpoint '%s' ", endpointId));
if (exposure != null) {
message.append(String.format("(%s) ", exposure.name().toLowerCase()));
}
message.append(String.format("is %s ", (enablement ? "enabled" : "disabled")));
if (defaultEnablement == DefaultEnablement.NEUTRAL) {
if (exposure != null) {
message.append(String.format("(default for %s endpoints)",
exposure.name().toLowerCase()));
}
else {
message.append("(default)");
}
}
else {
message.append("by default");
}
return message.toString();
}
private EndpointEnablement findGlobalEndpointEnablement(EndpointExposure exposure) {
if (exposure != null) {
EndpointEnablement result = findEnablement(getKey("default", exposure));
if (result != null) {
return result;
}
if (!exposure.isEnabledByDefault()) {
return getDefaultEndpointEnablement("default", false, exposure);
}
return null;
}
return findEnablementForAnyExposureTechnology("default");
}
private EndpointEnablement findEnablementForAnyExposureTechnology(String endpointId) {
for (EndpointExposure candidate : EndpointExposure.values()) {
EndpointEnablement result = findEnablementForExposureTechnology(endpointId,
candidate);
if (result != null && result.isEnabled()) {
return result;
}
}
return null;
}
private EndpointEnablement findEnablementForExposureTechnology(String endpointId,
EndpointExposure exposure) {
String endpointTypeKey = getKey(endpointId, exposure);
return findEnablement(endpointTypeKey);
}
private EndpointEnablement getDefaultEndpointEnablement(String endpointId,
boolean enabledByDefault, EndpointExposure exposure) {
return new EndpointEnablement(enabledByDefault,
createDefaultEnablementMessage(endpointId, enabledByDefault, exposure));
}
private String createDefaultEnablementMessage(String endpointId,
boolean enabledByDefault, EndpointExposure exposure) {
StringBuilder message = new StringBuilder();
message.append(String.format("endpoint '%s' ", endpointId));
if (exposure != null) {
message.append(String.format("(%s) ", exposure.name().toLowerCase()));
}
message.append(String.format("is %s by default",
(enabledByDefault ? "enabled" : "disabled")));
return message.toString();
}
private String getKey(String endpointId, EndpointExposure exposure) {
return getKey(endpointId, exposure.name().toLowerCase() + ".enabled");
}
private String getKey(String endpointId, String suffix) {
return "endpoints." + endpointId + "." + suffix;
}
/**
* Return an {@link EndpointEnablement} for the specified key if it is set or
* {@code null} if the key is not present in the environment.
* @param key the key to check
* @return the outcome or {@code null} if the key is no set
*/
private EndpointEnablement findEnablement(String key) {
if (this.environment.containsProperty(key)) {
boolean match = this.environment.getProperty(key, Boolean.class, true);
return new EndpointEnablement(match, String.format("found property %s", key));
}
return null;
}
}
......@@ -16,42 +16,34 @@
package org.springframework.boot.actuate.autoconfigure.endpoint;
import java.util.function.Function;
import org.springframework.boot.actuate.endpoint.cache.CachingOperationInvokerAdvisor;
import org.springframework.core.env.PropertyResolver;
/**
* Determines if an endpoint is enabled or not.
* Function for use with {@link CachingOperationInvokerAdvisor} that extracts caching
* time-to-live from a {@link PropertyResolver resolved property}.
*
* @author Stephane Nicoll
* @since 2.0.0
* @author Phillip Webb
*/
public final class EndpointEnablement {
private final boolean enabled;
class EndpointIdTimeToLivePropertyFunction implements Function<String, Long> {
private final String reason;
/**
* Creates a new instance.
* @param enabled whether or not the endpoint is enabled
* @param reason a human readable reason of the decision
*/
EndpointEnablement(boolean enabled, String reason) {
this.enabled = enabled;
this.reason = reason;
}
private final PropertyResolver propertyResolver;
/**
* Return whether or not the endpoint is enabled.
* @return {@code true} if the endpoint is enabled, {@code false} otherwise
* Create a new instance with the {@link PropertyResolver} to use.
* @param propertyResolver the environment
*/
public boolean isEnabled() {
return this.enabled;
EndpointIdTimeToLivePropertyFunction(PropertyResolver propertyResolver) {
this.propertyResolver = propertyResolver;
}
/**
* Return a human readable reason of the decision.
* @return the reason of the endpoint's enablement
*/
public String getReason() {
return this.reason;
@Override
public Long apply(String endpointId) {
String key = String.format("management.endpoint.%s.cache.time-to-live",
endpointId);
return this.propertyResolver.getProperty(key, Long.class);
}
}
/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.endpoint;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.boot.actuate.endpoint.EndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.EndpointFilter;
import org.springframework.boot.actuate.endpoint.EndpointInfo;
import org.springframework.boot.actuate.endpoint.Operation;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.core.env.Environment;
import org.springframework.util.Assert;
/**
* {@link EndpointFilter} that will filter endpoints based on {@code expose} and
* {@code exclude} properties.
*
* @param <T> The operation type
* @author Phillip Webb
* @since 2.0.0
*/
public class ExposeExcludePropertyEndpointFilter<T extends Operation>
implements EndpointFilter<T> {
private final Class<? extends EndpointDiscoverer<T>> discovererType;
private final Set<String> expose;
private final Set<String> exclude;
private final Set<String> exposeDefaults;
public ExposeExcludePropertyEndpointFilter(
Class<? extends EndpointDiscoverer<T>> discovererType,
Environment environment, String prefix, String... exposeDefaults) {
Assert.notNull(discovererType, "Discoverer Type must not be null");
Assert.notNull(environment, "Environment must not be null");
Assert.hasText(prefix, "Prefix must not be empty");
Binder binder = Binder.get(environment);
this.discovererType = discovererType;
this.expose = bind(binder, prefix + ".expose");
this.exclude = bind(binder, prefix + ".exclude");
this.exposeDefaults = asSet(Arrays.asList(exposeDefaults));
}
public ExposeExcludePropertyEndpointFilter(
Class<? extends EndpointDiscoverer<T>> discovererType,
Collection<String> expose, Collection<String> exclude,
String... exposeDefaults) {
Assert.notNull(discovererType, "Discoverer Type must not be null");
this.discovererType = discovererType;
this.expose = asSet(expose);
this.exclude = asSet(exclude);
this.exposeDefaults = asSet(Arrays.asList(exposeDefaults));
}
private Set<String> bind(Binder binder, String name) {
return asSet(binder.bind(name, Bindable.listOf(String.class))
.orElseGet(ArrayList::new));
}
private Set<String> asSet(Collection<String> items) {
if (items == null) {
return Collections.emptySet();
}
return items.stream().map(String::toLowerCase)
.collect(Collectors.toCollection(HashSet::new));
}
@Override
public boolean match(EndpointInfo<T> info, EndpointDiscoverer<T> discoverer) {
if (this.discovererType.isInstance(discoverer)) {
return isExposed(info) && !isExcluded(info);
}
return true;
}
private boolean isExposed(EndpointInfo<T> info) {
if (this.expose.isEmpty()) {
return this.exposeDefaults.contains("*")
|| contains(this.exposeDefaults, info);
}
return this.expose.contains("*") || contains(this.expose, info);
}
private boolean isExcluded(EndpointInfo<T> info) {
if (this.exclude.isEmpty()) {
return false;
}
return this.exclude.contains("*") || contains(this.exclude, info);
}
private boolean contains(Set<String> items, EndpointInfo<T> info) {
return items.contains(info.getId().toLowerCase());
}
}
......@@ -22,63 +22,15 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.actuate.endpoint.DefaultEnablement;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.context.annotation.Conditional;
import org.springframework.core.env.Environment;
/**
* {@link Conditional} that checks whether an endpoint is enabled or not. Matches
* according to the {@code defaultEnablement} and {@code types} flag that the
* {@link Endpoint} may be restricted to.
* <p>
* When an endpoint uses {@link DefaultEnablement#DISABLED}, it will only be enabled if
* {@code endpoint.<name>.enabled}, {@code endpoint.<name>.jmx.enabled} or
* {@code endpoint.<name>.web.enabled} is {@code true}.
* <p>
* When an endpoint uses {@link DefaultEnablement#ENABLED}, it will be enabled unless
* {@code endpoint.<name>.enabled}, {@code endpoint.<name>.jmx.enabled} or
* {@code endpoint.<name>.web.enabled} is {@code false}.
* <p>
* When an endpoint uses {@link DefaultEnablement#NEUTRAL}, it will be enabled if
* {@code endpoint.default.enabled}, {@code endpoint.default.jmx.enabled} or
* {@code endpoint.default.web.enabled} is {@code true} and
* {@code endpoint.<name>.enabled}, {@code endpoint.<name>.jmx.enabled} or
* {@code endpoint.<name>.web.enabled} has not been set to {@code false}.
* <p>
* If any properties are set, they are evaluated from most to least specific, e.g.
* considering a web endpoint with id {@code foo}:
* <ol>
* <li>endpoints.foo.web.enabled</li>
* <li>endpoints.foo.enabled</li>
* <li>endpoints.default.web.enabled</li>
* <li>endpoints.default.enabled</li>
* </ol>
* For instance if {@code endpoints.default.enabled} is {@code false} but
* {@code endpoints.<name>.enabled} is {@code true}, the condition will match.
* <p>
* This condition must be placed on a {@code @Bean} method producing an endpoint as its id
* and other attributes are inferred from the {@link Endpoint} annotation set on the
* return type of the factory method. Consider the following valid example:
*
* <pre class="code">
* &#064;Configuration
* public class MyAutoConfiguration {
*
* &#064;ConditionalOnEnabledEndpoint
* &#064;Bean
* public MyEndpoint myEndpoint() {
* ...
* }
*
* &#064;Endpoint(id = "my", defaultEnablement = DefaultEnablement.DISABLED)
* static class MyEndpoint { ... }
*
* }</pre>
* <p>
*
* In the sample above the condition will be evaluated with the attributes specified on
* {@code MyEndpoint}. In particular, in the absence of any property in the environment,
* the condition will not match as this endpoint is disabled by default.
* according to the endpoints specific {@link Environment} property, falling back to
* {@code management.endpoints.enabled-by-default} or failing that
* {@link Endpoint#enableByDefault()}.
*
* @author Stephane Nicoll
* @since 2.0.0
......
......@@ -16,45 +16,62 @@
package org.springframework.boot.actuate.autoconfigure.endpoint.condition;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointEnablement;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointEnablementProvider;
import org.springframework.boot.actuate.endpoint.DefaultEnablement;
import org.springframework.boot.actuate.endpoint.EndpointExposure;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.jmx.annotation.JmxEndpointExtension;
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointExtension;
import org.springframework.boot.actuate.endpoint.annotation.EndpointExtension;
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* A condition that checks if an endpoint is enabled.
*
* @author Stephane Nicoll
* @author Andy Wilkinson
* @author Phillip Webb
* @see ConditionalOnEnabledEndpoint
*/
class OnEnabledEndpointCondition extends SpringBootCondition {
private static final String ENABLED_BY_DEFAULT_KEY = "management.endpoints.enabled-by-default";
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
EndpointAttributes attributes = getEndpointAttributes(context, metadata);
EndpointEnablement endpointEnablement = attributes
.getEnablement(new EndpointEnablementProvider(context.getEnvironment()));
return new ConditionOutcome(endpointEnablement.isEnabled(),
ConditionMessage.forCondition(ConditionalOnEnabledEndpoint.class)
.because(endpointEnablement.getReason()));
AnnotationAttributes attributes = getEndpointAttributes(context, metadata);
String id = attributes.getString("id");
String key = "management.endpoint." + id + ".enabled";
Boolean userDefinedEnabled = context.getEnvironment().getProperty(key,
Boolean.class);
if (userDefinedEnabled != null) {
return new ConditionOutcome(userDefinedEnabled,
ConditionMessage.forCondition(ConditionalOnEnabledEndpoint.class)
.because("found property " + key + " with value "
+ userDefinedEnabled));
}
Boolean userDefinedDefault = context.getEnvironment()
.getProperty(ENABLED_BY_DEFAULT_KEY, Boolean.class);
if (userDefinedDefault != null) {
return new ConditionOutcome(userDefinedDefault,
ConditionMessage.forCondition(ConditionalOnEnabledEndpoint.class)
.because("no property " + key
+ " found so using user defined default from "
+ ENABLED_BY_DEFAULT_KEY));
}
boolean endpointDefault = attributes.getBoolean("enableByDefault");
return new ConditionOutcome(endpointDefault,
ConditionMessage.forCondition(ConditionalOnEnabledEndpoint.class).because(
"no property " + key + " found so using endpoint default"));
}
private EndpointAttributes getEndpointAttributes(ConditionContext context,
private AnnotationAttributes getEndpointAttributes(ConditionContext context,
AnnotatedTypeMetadata metadata) {
Assert.state(
metadata instanceof MethodMetadata
......@@ -63,77 +80,35 @@ class OnEnabledEndpointCondition extends SpringBootCondition {
return getEndpointAttributes(context, (MethodMetadata) metadata);
}
private EndpointAttributes getEndpointAttributes(ConditionContext context,
MethodMetadata methodMetadata) {
private AnnotationAttributes getEndpointAttributes(ConditionContext context,
MethodMetadata metadata) {
// We should be safe to load at this point since we are in the REGISTER_BEAN phase
try {
// We should be safe to load at this point since we are in the
// REGISTER_BEAN phase
Class<?> returnType = ClassUtils.forName(methodMetadata.getReturnTypeName(),
Class<?> returnType = ClassUtils.forName(metadata.getReturnTypeName(),
context.getClassLoader());
return extractEndpointAttributes(returnType);
return getEndpointAttributes(returnType);
}
catch (Throwable ex) {
throw new IllegalStateException("Failed to extract endpoint id for "
+ methodMetadata.getDeclaringClassName() + "."
+ methodMetadata.getMethodName(), ex);
}
}
protected EndpointAttributes extractEndpointAttributes(Class<?> type) {
EndpointAttributes attributes = extractEndpointAttributesFromEndpoint(type);
if (attributes != null) {
return attributes;
}
JmxEndpointExtension jmxExtension = AnnotationUtils.findAnnotation(type,
JmxEndpointExtension.class);
if (jmxExtension != null) {
return extractEndpointAttributes(jmxExtension.endpoint());
}
WebEndpointExtension webExtension = AnnotationUtils.findAnnotation(type,
WebEndpointExtension.class);
if (webExtension != null) {
return extractEndpointAttributes(webExtension.endpoint());
}
throw new IllegalStateException(
"OnEnabledEndpointCondition may only be used on @Bean methods that return"
+ " @Endpoint, @JmxEndpointExtension, or @WebEndpointExtension");
}
private EndpointAttributes extractEndpointAttributesFromEndpoint(
Class<?> endpointClass) {
Endpoint endpoint = AnnotationUtils.findAnnotation(endpointClass, Endpoint.class);
if (endpoint == null) {
return null;
+ metadata.getDeclaringClassName() + "." + metadata.getMethodName(),
ex);
}
// If both types are set, all exposure technologies are exposed
EndpointExposure[] exposures = endpoint.exposure();
return new EndpointAttributes(endpoint.id(), endpoint.defaultEnablement(),
(exposures.length == 1 ? exposures[0] : null));
}
private static class EndpointAttributes {
private final String id;
private final DefaultEnablement defaultEnablement;
private final EndpointExposure exposure;
EndpointAttributes(String id, DefaultEnablement defaultEnablement,
EndpointExposure exposure) {
if (!StringUtils.hasText(id)) {
throw new IllegalStateException("Endpoint id could not be determined");
protected AnnotationAttributes getEndpointAttributes(Class<?> type) {
AnnotationAttributes attributes = AnnotatedElementUtils
.findMergedAnnotationAttributes(type, Endpoint.class, true, true);
if (attributes == null) {
attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(type,
EndpointExtension.class, false, true);
if (attributes != null) {
return getEndpointAttributes(attributes.getClass("endpoint"));
}
this.id = id;
this.defaultEnablement = defaultEnablement;
this.exposure = exposure;
}
public EndpointEnablement getEnablement(EndpointEnablementProvider provider) {
return provider.getEndpointEnablement(this.id, this.defaultEnablement,
this.exposure);
}
Assert.state(attributes != null,
"OnEnabledEndpointCondition may only be used on @Bean methods that "
+ "return an @Endpoint or and @EndpointExtension");
return attributes;
}
}
......@@ -36,13 +36,13 @@ import org.springframework.util.StringUtils;
*/
class DefaultEndpointObjectNameFactory implements EndpointObjectNameFactory {
private final JmxEndpointExporterProperties properties;
private final JmxEndpointProperties properties;
private final MBeanServer mBeanServer;
private final String contextId;
DefaultEndpointObjectNameFactory(JmxEndpointExporterProperties properties,
DefaultEndpointObjectNameFactory(JmxEndpointProperties properties,
MBeanServer mBeanServer, String contextId) {
this.properties = properties;
this.mBeanServer = mBeanServer;
......
......@@ -16,21 +16,25 @@
package org.springframework.boot.actuate.autoconfigure.endpoint.jmx;
import java.util.Collection;
import javax.management.MBeanServer;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.autoconfigure.endpoint.DefaultCachingConfigurationFactory;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointProvider;
import org.springframework.boot.actuate.endpoint.EndpointExposure;
import org.springframework.boot.actuate.endpoint.ParameterMapper;
import org.springframework.boot.actuate.autoconfigure.endpoint.ExposeExcludePropertyEndpointFilter;
import org.springframework.boot.actuate.endpoint.EndpointFilter;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.jmx.EndpointMBeanRegistrar;
import org.springframework.boot.actuate.endpoint.jmx.JmxEndpointOperation;
import org.springframework.boot.actuate.endpoint.jmx.EndpointObjectNameFactory;
import org.springframework.boot.actuate.endpoint.jmx.JmxOperation;
import org.springframework.boot.actuate.endpoint.jmx.annotation.JmxAnnotationEndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.reflect.OperationMethodInvokerAdvisor;
import org.springframework.boot.actuate.endpoint.reflect.ParameterMapper;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
......@@ -47,36 +51,49 @@ import org.springframework.util.ObjectUtils;
* @since 2.0.0
*/
@AutoConfigureAfter(JmxAutoConfiguration.class)
@EnableConfigurationProperties(JmxEndpointExporterProperties.class)
@EnableConfigurationProperties(JmxEndpointProperties.class)
@ConditionalOnProperty(name = "management.endpoints.jmx.enabled", matchIfMissing = true)
public class JmxEndpointAutoConfiguration {
private final ApplicationContext applicationContext;
public JmxEndpointAutoConfiguration(ApplicationContext applicationContext) {
private final JmxEndpointProperties properties;
public JmxEndpointAutoConfiguration(ApplicationContext applicationContext,
JmxEndpointProperties properties) {
this.applicationContext = applicationContext;
this.properties = properties;
}
@Bean
public JmxAnnotationEndpointDiscoverer jmxEndpointDiscoverer(
public JmxAnnotationEndpointDiscoverer jmxAnnotationEndpointDiscoverer(
ParameterMapper parameterMapper,
DefaultCachingConfigurationFactory cachingConfigurationFactory) {
Collection<OperationMethodInvokerAdvisor> invokerAdvisors,
Collection<EndpointFilter<JmxOperation>> filters) {
return new JmxAnnotationEndpointDiscoverer(this.applicationContext,
parameterMapper, cachingConfigurationFactory);
parameterMapper, invokerAdvisors, filters);
}
@ConditionalOnSingleCandidate(MBeanServer.class)
@Bean
public JmxEndpointExporter jmxMBeanExporter(JmxEndpointExporterProperties properties,
@ConditionalOnSingleCandidate(MBeanServer.class)
public JmxEndpointExporter jmxMBeanExporter(
JmxAnnotationEndpointDiscoverer jmxAnnotationEndpointDiscoverer,
MBeanServer mBeanServer, JmxAnnotationEndpointDiscoverer endpointDiscoverer,
ObjectProvider<ObjectMapper> objectMapper) {
EndpointProvider<JmxEndpointOperation> endpointProvider = new EndpointProvider<>(
this.applicationContext.getEnvironment(), endpointDiscoverer,
EndpointExposure.JMX);
EndpointMBeanRegistrar endpointMBeanRegistrar = new EndpointMBeanRegistrar(
mBeanServer, new DefaultEndpointObjectNameFactory(properties, mBeanServer,
ObjectUtils.getIdentityHexString(this.applicationContext)));
return new JmxEndpointExporter(endpointProvider, endpointMBeanRegistrar,
EndpointObjectNameFactory objectNameFactory = new DefaultEndpointObjectNameFactory(
this.properties, mBeanServer,
ObjectUtils.getIdentityHexString(this.applicationContext));
EndpointMBeanRegistrar registrar = new EndpointMBeanRegistrar(mBeanServer,
objectNameFactory);
return new JmxEndpointExporter(jmxAnnotationEndpointDiscoverer, registrar,
objectMapper.getIfAvailable(ObjectMapper::new));
}
@Bean
public ExposeExcludePropertyEndpointFilter<JmxOperation> jmxIncludeExcludePropertyEndpointFilter() {
return new ExposeExcludePropertyEndpointFilter<>(
JmxAnnotationEndpointDiscoverer.class, this.properties.getExpose(),
this.properties.getExclude(), "*");
}
}
......@@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.management.MBeanServer;
import javax.management.ObjectName;
......@@ -29,13 +30,13 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointProvider;
import org.springframework.boot.actuate.endpoint.EndpointInfo;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.jmx.EndpointMBean;
import org.springframework.boot.actuate.endpoint.jmx.EndpointMBeanRegistrar;
import org.springframework.boot.actuate.endpoint.jmx.JmxEndpointMBeanFactory;
import org.springframework.boot.actuate.endpoint.jmx.JmxEndpointOperation;
import org.springframework.boot.actuate.endpoint.jmx.JmxOperation;
import org.springframework.boot.actuate.endpoint.jmx.JmxOperationResponseMapper;
import org.springframework.boot.actuate.endpoint.jmx.annotation.JmxAnnotationEndpointDiscoverer;
/**
* Exports all available {@link Endpoint} to a configurable {@link MBeanServer}.
......@@ -44,7 +45,7 @@ import org.springframework.boot.actuate.endpoint.jmx.JmxOperationResponseMapper;
*/
class JmxEndpointExporter implements InitializingBean, DisposableBean {
private final EndpointProvider<JmxEndpointOperation> endpointProvider;
private final JmxAnnotationEndpointDiscoverer endpointDiscoverer;
private final EndpointMBeanRegistrar endpointMBeanRegistrar;
......@@ -52,9 +53,9 @@ class JmxEndpointExporter implements InitializingBean, DisposableBean {
private Collection<ObjectName> registeredObjectNames;
JmxEndpointExporter(EndpointProvider<JmxEndpointOperation> endpointProvider,
JmxEndpointExporter(JmxAnnotationEndpointDiscoverer endpointDiscoverer,
EndpointMBeanRegistrar endpointMBeanRegistrar, ObjectMapper objectMapper) {
this.endpointProvider = endpointProvider;
this.endpointDiscoverer = endpointDiscoverer;
this.endpointMBeanRegistrar = endpointMBeanRegistrar;
DataConverter dataConverter = new DataConverter(objectMapper);
this.mBeanFactory = new JmxEndpointMBeanFactory(dataConverter);
......@@ -65,21 +66,19 @@ class JmxEndpointExporter implements InitializingBean, DisposableBean {
this.registeredObjectNames = registerEndpointMBeans();
}
private Collection<ObjectName> registerEndpointMBeans() {
Collection<EndpointInfo<JmxOperation>> endpoints = this.endpointDiscoverer
.discoverEndpoints();
return this.mBeanFactory.createMBeans(endpoints).stream()
.map(this.endpointMBeanRegistrar::registerEndpointMBean)
.collect(Collectors.toCollection(ArrayList::new));
}
@Override
public void destroy() throws Exception {
unregisterEndpointMBeans(this.registeredObjectNames);
}
private Collection<ObjectName> registerEndpointMBeans() {
List<ObjectName> objectNames = new ArrayList<>();
Collection<EndpointMBean> mBeans = this.mBeanFactory
.createMBeans(this.endpointProvider.getEndpoints());
for (EndpointMBean mBean : mBeans) {
objectNames.add(this.endpointMBeanRegistrar.registerEndpointMBean(mBean));
}
return objectNames;
}
private void unregisterEndpointMBeans(Collection<ObjectName> objectNames) {
objectNames.forEach(this.endpointMBeanRegistrar::unregisterEndpointMbean);
......
......@@ -16,7 +16,9 @@
package org.springframework.boot.actuate.autoconfigure.endpoint.jmx;
import java.util.LinkedHashSet;
import java.util.Properties;
import java.util.Set;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.env.Environment;
......@@ -29,7 +31,22 @@ import org.springframework.util.StringUtils;
* @since 2.0.0
*/
@ConfigurationProperties("management.endpoints.jmx")
public class JmxEndpointExporterProperties {
public class JmxEndpointProperties {
/**
* Whether JMX endpoints are enabled.
*/
private boolean enabled;
/**
* The IDs of endpoints that should be exposed or '*' for all.
*/
private Set<String> expose = new LinkedHashSet<>();
/**
* The IDs of endpoints that should be excluded.
*/
private Set<String> exclude = new LinkedHashSet<>();
/**
* Endpoints JMX domain name. Fallback to 'spring.jmx.default-domain' if set.
......@@ -47,13 +64,37 @@ public class JmxEndpointExporterProperties {
*/
private final Properties staticNames = new Properties();
public JmxEndpointExporterProperties(Environment environment) {
public JmxEndpointProperties(Environment environment) {
String defaultDomain = environment.getProperty("spring.jmx.default-domain");
if (StringUtils.hasText(defaultDomain)) {
this.domain = defaultDomain;
}
}
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public Set<String> getExpose() {
return this.expose;
}
public void setExpose(Set<String> expose) {
this.expose = expose;
}
public Set<String> getExclude() {
return this.exclude;
}
public void setExclude(Set<String> exclude) {
this.exclude = exclude;
}
public String getDomain() {
return this.domain;
}
......
......@@ -16,13 +16,13 @@
package org.springframework.boot.actuate.autoconfigure.endpoint.web;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointProvider;
import org.springframework.boot.actuate.endpoint.EndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.EndpointInfo;
import org.springframework.boot.actuate.endpoint.web.WebEndpointOperation;
import org.springframework.boot.actuate.endpoint.web.WebOperation;
import org.springframework.util.Assert;
/**
......@@ -33,29 +33,34 @@ import org.springframework.util.Assert;
*/
public class DefaultEndpointPathProvider implements EndpointPathProvider {
private final Collection<EndpointInfo<WebEndpointOperation>> endpoints;
private final String basePath;
public DefaultEndpointPathProvider(EndpointProvider<WebEndpointOperation> provider,
private final EndpointDiscoverer<WebOperation> endpointDiscoverer;
public DefaultEndpointPathProvider(
EndpointDiscoverer<WebOperation> endpointDiscoverer,
WebEndpointProperties webEndpointProperties) {
this.endpoints = provider.getEndpoints();
this.endpointDiscoverer = endpointDiscoverer;
this.basePath = webEndpointProperties.getBasePath();
}
@Override
public List<String> getPaths() {
return this.endpoints.stream().map(this::getPath).collect(Collectors.toList());
return getEndpoints().map(this::getPath).collect(Collectors.toList());
}
@Override
public String getPath(String id) {
Assert.notNull(id, "ID must not be null");
return this.endpoints.stream().filter((info) -> id.equals(info.getId()))
.findFirst().map(this::getPath).orElse(null);
return getEndpoints().filter((info) -> id.equals(info.getId())).findFirst()
.map(this::getPath).orElse(null);
}
private Stream<EndpointInfo<WebOperation>> getEndpoints() {
return this.endpointDiscoverer.discoverEndpoints().stream();
}
private String getPath(EndpointInfo<WebEndpointOperation> endpointInfo) {
private String getPath(EndpointInfo<WebOperation> endpointInfo) {
return this.basePath + "/" + endpointInfo.getId();
}
......
......@@ -14,7 +14,9 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.endpoint;
package org.springframework.boot.actuate.autoconfigure.endpoint.web;
import java.util.Map;
import org.springframework.boot.actuate.endpoint.web.EndpointPathResolver;
import org.springframework.core.env.Environment;
......@@ -27,16 +29,15 @@ import org.springframework.core.env.Environment;
*/
class DefaultEndpointPathResolver implements EndpointPathResolver {
private final Environment environment;
private final Map<String, String> pathMapping;
DefaultEndpointPathResolver(Environment environment) {
this.environment = environment;
DefaultEndpointPathResolver(Map<String, String> pathMapping) {
this.pathMapping = pathMapping;
}
@Override
public String resolvePath(String endpointId) {
String key = String.format("endpoints.%s.web.path", endpointId);
return this.environment.getProperty(key, String.class, endpointId);
return this.pathMapping.getOrDefault(endpointId, endpointId);
}
}
/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.endpoint.web;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.ExposeExcludePropertyEndpointFilter;
import org.springframework.boot.actuate.endpoint.EndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.EndpointFilter;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
import org.springframework.boot.actuate.endpoint.reflect.OperationMethodInvokerAdvisor;
import org.springframework.boot.actuate.endpoint.reflect.ParameterMapper;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.EndpointPathResolver;
import org.springframework.boot.actuate.endpoint.web.WebOperation;
import org.springframework.boot.actuate.endpoint.web.annotation.WebAnnotationEndpointDiscoverer;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* {@link EnableAutoConfiguration Auto-configuration} for web {@link Endpoint} support.
*
* @author Phillip Webb
* @author Stephane Nicoll
* @author Phillip Webb
* @since 2.0.0
*/
@Configuration
@ConditionalOnWebApplication
@AutoConfigureAfter(EndpointAutoConfiguration.class)
@EnableConfigurationProperties(WebEndpointProperties.class)
@ConditionalOnProperty(name = "management.endpoints.web.enabled", matchIfMissing = true)
public class WebEndpointAutoConfiguration {
private static final List<String> MEDIA_TYPES = Arrays
.asList(ActuatorMediaType.V2_JSON, "application/json");
private final ApplicationContext applicationContext;
private final WebEndpointProperties properties;
public WebEndpointAutoConfiguration(ApplicationContext applicationContext,
WebEndpointProperties properties) {
this.applicationContext = applicationContext;
this.properties = properties;
}
@Bean
@ConditionalOnMissingBean
public EndpointPathResolver endpointPathResolver() {
return new DefaultEndpointPathResolver(this.properties.getPathMapping());
}
@Bean
@ConditionalOnMissingBean
public WebAnnotationEndpointDiscoverer webAnnotationEndpointDiscoverer(
ParameterMapper parameterMapper, EndpointPathResolver endpointPathResolver,
Collection<OperationMethodInvokerAdvisor> invokerAdvisors,
Collection<EndpointFilter<WebOperation>> filters) {
return new WebAnnotationEndpointDiscoverer(this.applicationContext,
parameterMapper, endpointMediaTypes(), endpointPathResolver,
invokerAdvisors, filters);
}
@Bean
@ConditionalOnMissingBean
public EndpointMediaTypes endpointMediaTypes() {
return new EndpointMediaTypes(MEDIA_TYPES, MEDIA_TYPES);
}
@Bean
@ConditionalOnMissingBean
public EndpointPathProvider endpointPathProvider(
EndpointDiscoverer<WebOperation> endpointDiscoverer,
WebEndpointProperties webEndpointProperties) {
return new DefaultEndpointPathProvider(endpointDiscoverer, webEndpointProperties);
}
@Bean
public ExposeExcludePropertyEndpointFilter<WebOperation> webIncludeExcludePropertyEndpointFilter() {
return new ExposeExcludePropertyEndpointFilter<>(
WebAnnotationEndpointDiscoverer.class, this.properties.getExpose(),
this.properties.getExclude(), "info", "status");
}
}
......@@ -16,23 +16,57 @@
package org.springframework.boot.actuate.autoconfigure.endpoint.web;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Configuration properties for web management endpoints.
*
* @author Madhura Bhave
* @author Phillip Webb
* @since 2.0.0
*/
@ConfigurationProperties(prefix = "management.endpoints.web")
public class WebEndpointProperties {
/**
* Whether web endpoints are enabled.
*/
private boolean enabled;
/**
* The base-path for the web endpoints. Relative to `server.context-path` or
* `management.server.context-path`, if `management.server.port` is different.
*/
private String basePath = "/application";
/**
* The IDs of endpoints that should be exposed or '*' for all.
*/
private Set<String> expose = new LinkedHashSet<>();
/**
* The IDs of endpoints that should be excluded.
*/
private Set<String> exclude = new LinkedHashSet<>();
/**
* Mapping between endpoint IDs and the path that should expose them.
*/
private Map<String, String> pathMapping = new LinkedHashMap<>();
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getBasePath() {
return this.basePath;
}
......@@ -41,4 +75,28 @@ public class WebEndpointProperties {
this.basePath = basePath;
}
public Set<String> getExpose() {
return this.expose;
}
public void setExpose(Set<String> expose) {
this.expose = expose;
}
public Set<String> getExclude() {
return this.exclude;
}
public void setExclude(Set<String> exclude) {
this.exclude = exclude;
}
public Map<String, String> getPathMapping() {
return this.pathMapping;
}
public void setPathMapping(Map<String, String> pathMapping) {
this.pathMapping = pathMapping;
}
}
......@@ -20,14 +20,11 @@ import java.util.HashSet;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointProvider;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.DefaultEndpointPathProvider;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.EndpointPathProvider;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.WebEndpointOperation;
import org.springframework.boot.actuate.endpoint.web.annotation.WebAnnotationEndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.web.jersey.JerseyEndpointResourceFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
......@@ -49,27 +46,19 @@ import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(ResourceConfig.class)
@ConditionalOnBean(ResourceConfig.class)
@ConditionalOnBean({ ResourceConfig.class, WebAnnotationEndpointDiscoverer.class })
@ConditionalOnMissingBean(type = "org.springframework.web.servlet.DispatcherServlet")
class JerseyWebEndpointManagementContextConfiguration {
@Bean
public ResourceConfigCustomizer webEndpointRegistrar(
EndpointProvider<WebEndpointOperation> provider,
WebAnnotationEndpointDiscoverer endpointDiscoverer,
EndpointMediaTypes endpointMediaTypes,
WebEndpointProperties webEndpointProperties) {
return (resourceConfig) -> resourceConfig.registerResources(
new HashSet<>(new JerseyEndpointResourceFactory().createEndpointResources(
new EndpointMapping(webEndpointProperties.getBasePath()),
provider.getEndpoints(), endpointMediaTypes)));
}
@Bean
@ConditionalOnMissingBean
public EndpointPathProvider endpointPathProvider(
EndpointProvider<WebEndpointOperation> provider,
WebEndpointProperties webEndpointProperties) {
return new DefaultEndpointPathProvider(provider, webEndpointProperties);
endpointDiscoverer.discoverEndpoints(), endpointMediaTypes)));
}
}
......@@ -16,15 +16,13 @@
package org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointProvider;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.DefaultEndpointPathProvider;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.EndpointPathProvider;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.WebEndpointOperation;
import org.springframework.boot.actuate.endpoint.web.annotation.WebAnnotationEndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
......@@ -40,25 +38,18 @@ import org.springframework.context.annotation.Bean;
*/
@ManagementContextConfiguration
@ConditionalOnWebApplication(type = Type.REACTIVE)
@ConditionalOnBean(WebAnnotationEndpointDiscoverer.class)
public class WebFluxEndpointManagementContextConfiguration {
@Bean
@ConditionalOnMissingBean
public WebFluxEndpointHandlerMapping webEndpointReactiveHandlerMapping(
EndpointProvider<WebEndpointOperation> provider,
WebAnnotationEndpointDiscoverer endpointDiscoverer,
EndpointMediaTypes endpointMediaTypes,
WebEndpointProperties webEndpointProperties) {
return new WebFluxEndpointHandlerMapping(
new EndpointMapping(webEndpointProperties.getBasePath()),
provider.getEndpoints(), endpointMediaTypes);
}
@Bean
@ConditionalOnMissingBean
public EndpointPathProvider endpointPathProvider(
EndpointProvider<WebEndpointOperation> provider,
WebEndpointProperties webEndpointProperties) {
return new DefaultEndpointPathProvider(provider, webEndpointProperties);
endpointDiscoverer.discoverEndpoints(), endpointMediaTypes);
}
}
......@@ -27,7 +27,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
* @author Andy Wilkinson
* @since 2.0.0
*/
@ConfigurationProperties(prefix = "management.endpoints.cors")
@ConfigurationProperties(prefix = "management.endpoints.web.cors")
public class CorsEndpointProperties {
/**
......
......@@ -16,15 +16,11 @@
package org.springframework.boot.actuate.autoconfigure.endpoint.web.servlet;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointProvider;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.DefaultEndpointPathProvider;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.EndpointPathProvider;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.WebEndpointOperation;
import org.springframework.boot.actuate.endpoint.web.annotation.WebAnnotationEndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
......@@ -45,35 +41,27 @@ import org.springframework.web.servlet.DispatcherServlet;
* @author Phillip Webb
* @since 2.0.0
*/
@ManagementContextConfiguration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
@ConditionalOnBean(DispatcherServlet.class)
@EnableConfigurationProperties({ CorsEndpointProperties.class,
WebEndpointProperties.class, ManagementServerProperties.class })
@ConditionalOnBean({ DispatcherServlet.class, WebAnnotationEndpointDiscoverer.class })
@EnableConfigurationProperties(CorsEndpointProperties.class)
public class WebMvcEndpointManagementContextConfiguration {
@Bean
@ConditionalOnMissingBean
public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(
EndpointProvider<WebEndpointOperation> provider,
WebAnnotationEndpointDiscoverer endpointDiscoverer,
EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties,
WebEndpointProperties webEndpointProperties) {
WebMvcEndpointHandlerMapping handlerMapping = new WebMvcEndpointHandlerMapping(
new EndpointMapping(webEndpointProperties.getBasePath()),
provider.getEndpoints(), endpointMediaTypes,
endpointDiscoverer.discoverEndpoints(), endpointMediaTypes,
getCorsConfiguration(corsProperties));
return handlerMapping;
}
@Bean
@ConditionalOnMissingBean
public EndpointPathProvider endpointPathProvider(
EndpointProvider<WebEndpointOperation> provider,
WebEndpointProperties webEndpointProperties) {
return new DefaultEndpointPathProvider(provider, webEndpointProperties);
}
private CorsConfiguration getCorsConfiguration(CorsEndpointProperties properties) {
if (CollectionUtils.isEmpty(properties.getAllowedOrigins())) {
return null;
......
......@@ -18,7 +18,7 @@ package org.springframework.boot.actuate.autoconfigure.env;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
import org.springframework.boot.actuate.env.EnvironmentEndpoint;
import org.springframework.boot.actuate.env.EnvironmentWebEndpointExtension;
import org.springframework.boot.actuate.env.EnvironmentEndpointWebExtension;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
......@@ -61,9 +61,9 @@ public class EnvironmentEndpointAutoConfiguration {
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
@ConditionalOnBean(EnvironmentEndpoint.class)
public EnvironmentWebEndpointExtension environmentWebEndpointExtension(
public EnvironmentEndpointWebExtension environmentWebEndpointExtension(
EnvironmentEndpoint environmentEndpoint) {
return new EnvironmentWebEndpointExtension(environmentEndpoint);
return new EnvironmentEndpointWebExtension(environmentEndpoint);
}
}
......@@ -25,7 +25,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
* @author Stephane Nicoll
* @since 2.0.0
*/
@ConfigurationProperties("endpoints.env")
@ConfigurationProperties("management.endpoint.env")
public class EnvironmentEndpointProperties {
/**
......
......@@ -25,15 +25,15 @@ import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfi
import org.springframework.boot.actuate.health.CompositeReactiveHealthIndicatorFactory;
import org.springframework.boot.actuate.health.HealthAggregator;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.boot.actuate.health.HealthEndpointWebExtension;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.health.HealthReactiveWebEndpointExtension;
import org.springframework.boot.actuate.health.HealthStatusHttpMapper;
import org.springframework.boot.actuate.health.HealthWebEndpointExtension;
import org.springframework.boot.actuate.health.OrderedHealthAggregator;
import org.springframework.boot.actuate.health.ReactiveHealthEndpointWebExtension;
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
import org.springframework.boot.actuate.health.ReactiveStatusEndpointWebExtension;
import org.springframework.boot.actuate.health.StatusEndpoint;
import org.springframework.boot.actuate.health.StatusReactiveWebEndpointExtension;
import org.springframework.boot.actuate.health.StatusWebEndpointExtension;
import org.springframework.boot.actuate.health.StatusEndpointWebExtension;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
......@@ -84,9 +84,9 @@ public class HealthWebEndpointManagementContextConfiguration {
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
@ConditionalOnBean(HealthEndpoint.class)
public HealthReactiveWebEndpointExtension healthWebEndpointExtension(
public ReactiveHealthEndpointWebExtension reactiveHealthEndpointWebExtension(
HealthStatusHttpMapper healthStatusHttpMapper) {
return new HealthReactiveWebEndpointExtension(this.reactiveHealthIndicator,
return new ReactiveHealthEndpointWebExtension(this.reactiveHealthIndicator,
healthStatusHttpMapper);
}
......@@ -94,9 +94,9 @@ public class HealthWebEndpointManagementContextConfiguration {
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
@ConditionalOnBean(StatusEndpoint.class)
public StatusReactiveWebEndpointExtension statusWebEndpointExtension(
public ReactiveStatusEndpointWebExtension reactiveStatusEndpointWebExtension(
HealthStatusHttpMapper healthStatusHttpMapper) {
return new StatusReactiveWebEndpointExtension(this.reactiveHealthIndicator,
return new ReactiveStatusEndpointWebExtension(this.reactiveHealthIndicator,
healthStatusHttpMapper);
}
......@@ -110,18 +110,18 @@ public class HealthWebEndpointManagementContextConfiguration {
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
@ConditionalOnBean(HealthEndpoint.class)
public HealthWebEndpointExtension healthWebEndpointExtension(
public HealthEndpointWebExtension healthEndpointWebExtension(
HealthEndpoint delegate, HealthStatusHttpMapper healthStatusHttpMapper) {
return new HealthWebEndpointExtension(delegate, healthStatusHttpMapper);
return new HealthEndpointWebExtension(delegate, healthStatusHttpMapper);
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
@ConditionalOnBean(StatusEndpoint.class)
public StatusWebEndpointExtension statusWebEndpointExtension(
public StatusEndpointWebExtension statusEndpointWebExtension(
StatusEndpoint delegate, HealthStatusHttpMapper healthStatusHttpMapper) {
return new StatusWebEndpointExtension(delegate, healthStatusHttpMapper);
return new StatusEndpointWebExtension(delegate, healthStatusHttpMapper);
}
}
......
......@@ -71,10 +71,11 @@ public class LogFileWebEndpointManagementContextConfiguration {
return ConditionOutcome
.match(message.found("logging.path").items(config));
}
config = environment.getProperty("endpoints.logfile.external-file");
config = environment.getProperty("management.endpoint.logfile.external-file");
if (StringUtils.hasText(config)) {
return ConditionOutcome.match(
message.found("endpoints.logfile.external-file").items(config));
return ConditionOutcome
.match(message.found("management.endpoint.logfile.external-file")
.items(config));
}
return ConditionOutcome.noMatch(message.didNotFind("logging file").atAll());
}
......
......@@ -27,7 +27,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
* @author Stephane Nicoll
* @since 2.0.0
*/
@ConfigurationProperties(prefix = "endpoints.logfile")
@ConfigurationProperties(prefix = "management.endpoint.logfile")
public class LogFileWebEndpointProperties {
/**
......
{"properties": [
{
"name": "endpoints.configprops.keys-to-sanitize",
"name": "management.endpoint.configprops.keys-to-sanitize",
"defaultValue": [
"password",
"secret",
......@@ -11,25 +11,12 @@
]
},
{
"name": "endpoints.default.enabled",
"name": "management.endpoints.enabled-by-default",
"type": "java.lang.Boolean",
"description": "Enable all endpoints by default.",
"defaultValue": true
},
{
"name": "endpoints.default.jmx.enabled",
"type": "java.lang.Boolean",
"description": "Enable all endpoints as JMX MBeans by default.",
"defaultValue": true
},
{
"name": "endpoints.default.web.enabled",
"type": "java.lang.Boolean",
"description": "Enable all endpoints as Web endpoints by default.",
"defaultValue": false
"description": "Enable or disable all endpoints by default."
},
{
"name": "endpoints.env.keys-to-sanitize",
"name": "management.endpoint.env.keys-to-sanitize",
"defaultValue": [
"password",
"secret",
......@@ -40,7 +27,7 @@
]
},
{
"name": "endpoints.trace.filter.enabled",
"name": "management.endpoint.trace.filter.enabled",
"type": "java.lang.Boolean",
"description": "Enable the trace servlet filter.",
"defaultValue": true,
......@@ -321,7 +308,7 @@
"type": "java.lang.Boolean",
"description": "Set whether credentials are supported. When not set, credentials are not supported.",
"deprecation": {
"replacement": "management.endpoints.cors.allow-credentials",
"replacement": "management.endpoints.web.cors.allow-credentials",
"level": "error"
}
},
......@@ -330,7 +317,7 @@
"type": "java.util.List<java.lang.String>",
"description": "Comma-separated list of headers to allow in a request. '*' allows all headers.",
"deprecation": {
"replacement": "management.endpoints.cors.allowed-headers",
"replacement": "management.endpoints.web.cors.allowed-headers",
"level": "error"
}
},
......@@ -339,7 +326,7 @@
"type": "java.util.List<java.lang.String>",
"description": "Comma-separated list of methods to allow. '*' allows all methods. When not set,\n defaults to GET.",
"deprecation": {
"replacement": "management.endpoints.cors.allowed-methods",
"replacement": "management.endpoints.web.cors.allowed-methods",
"level": "error"
}
},
......@@ -348,7 +335,7 @@
"type": "java.util.List<java.lang.String>",
"description": "Comma-separated list of origins to allow. '*' allows all origins. When not set,\n CORS support is disabled.",
"deprecation": {
"replacement": "management.endpoints.cors.allowed-origins",
"replacement": "management.endpoints.web.cors.allowed-origins",
"level": "error"
}
},
......@@ -357,7 +344,7 @@
"type": "java.util.List<java.lang.String>",
"description": "Comma-separated list of headers to include in a response.",
"deprecation": {
"replacement": "management.endpoints.cors.exposed-headers",
"replacement": "management.endpoints.web.cors.exposed-headers",
"level": "error"
}
},
......@@ -367,7 +354,7 @@
"description": "How long, in seconds, the response from a pre-flight request can be cached by\n clients.",
"defaultValue": 1800,
"deprecation": {
"replacement": "management.endpoints.cors.max-age",
"replacement": "management.endpoints.web.cors.max-age",
"level": "error"
}
},
......@@ -1202,7 +1189,7 @@
}
],"hints": [
{
"name": "management.endpoints.cors.allowed-headers",
"name": "management.endpoints.web.cors.allowed-headers",
"values": [
{
"value": "*"
......@@ -1215,7 +1202,7 @@
]
},
{
"name": "management.endpoints.cors.allowed-methods",
"name": "management.endpoints.web.cors.allowed-methods",
"values": [
{
"value": "*"
......@@ -1228,7 +1215,7 @@
]
},
{
"name": "management.endpoints.cors.allowed-origins",
"name": "management.endpoints.web.cors.allowed-origins",
"values": [
{
"value": "*"
......
......@@ -13,6 +13,7 @@ org.springframework.boot.actuate.autoconfigure.couchbase.CouchbaseHealthIndicato
org.springframework.boot.actuate.autoconfigure.elasticsearch.ElasticsearchHealthIndicatorAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.endpoint.jmx.JmxEndpointAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.env.EnvironmentEndpointAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.flyway.FlywayEndpointAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration,\
......
......@@ -19,8 +19,8 @@ package org.springframework.boot.actuate.autoconfigure.audit;
import org.junit.Test;
import org.springframework.boot.actuate.audit.AuditEventsEndpoint;
import org.springframework.boot.actuate.audit.AuditEventsEndpointWebExtension;
import org.springframework.boot.actuate.audit.AuditEventsJmxEndpointExtension;
import org.springframework.boot.actuate.audit.AuditEventsWebEndpointExtension;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
......@@ -54,17 +54,18 @@ public class AuditEventsEndpointAutoConfigurationTests {
@Test
public void runShouldHaveWebExtensionBean() {
this.contextRunner.run((context) -> assertThat(context)
.hasSingleBean(AuditEventsWebEndpointExtension.class));
.hasSingleBean(AuditEventsEndpointWebExtension.class));
}
@Test
public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointOrExtensionBean()
throws Exception {
this.contextRunner.withPropertyValues("endpoints.auditevents.enabled:false")
this.contextRunner
.withPropertyValues("management.endpoint.auditevents.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(AuditEventsEndpoint.class)
.doesNotHaveBean(AuditEventsJmxEndpointExtension.class)
.doesNotHaveBean(AuditEventsWebEndpointExtension.class));
.doesNotHaveBean(AuditEventsEndpointWebExtension.class));
}
}
......@@ -44,8 +44,9 @@ public class BeansEndpointAutoConfigurationTests {
@Test
public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean()
throws Exception {
this.contextRunner.withPropertyValues("endpoints.beans.enabled:false").run(
(context) -> assertThat(context).doesNotHaveBean(BeansEndpoint.class));
this.contextRunner.withPropertyValues("management.endpoint.beans.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(BeansEndpoint.class));
}
}
......@@ -28,15 +28,16 @@ import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.AccessLevel;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryAuthorizationException;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryAuthorizationException.Reason;
import org.springframework.boot.actuate.endpoint.ParameterMapper;
import org.springframework.boot.actuate.endpoint.EndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.boot.actuate.endpoint.cache.CachingConfiguration;
import org.springframework.boot.actuate.endpoint.convert.ConversionServiceParameterMapper;
import org.springframework.boot.actuate.endpoint.reflect.ParameterMapper;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.EndpointPathResolver;
import org.springframework.boot.actuate.endpoint.web.WebOperation;
import org.springframework.boot.actuate.endpoint.web.annotation.WebAnnotationEndpointDiscoverer;
import org.springframework.boot.endpoint.web.EndpointMapping;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
......@@ -217,7 +218,7 @@ public class CloudFoundryWebFluxEndpointIntegrationTests {
@Bean
public CloudFoundryWebFluxEndpointHandlerMapping cloudFoundryWebEndpointServletHandlerMapping(
WebAnnotationEndpointDiscoverer webEndpointDiscoverer,
EndpointDiscoverer<WebOperation> webEndpointDiscoverer,
EndpointMediaTypes endpointMediaTypes,
ReactiveCloudFoundrySecurityInterceptor interceptor) {
CorsConfiguration corsConfiguration = new CorsConfiguration();
......@@ -236,8 +237,8 @@ public class CloudFoundryWebFluxEndpointIntegrationTests {
ParameterMapper parameterMapper = new ConversionServiceParameterMapper(
DefaultConversionService.getSharedInstance());
return new WebAnnotationEndpointDiscoverer(applicationContext,
parameterMapper, (id) -> new CachingConfiguration(0),
endpointMediaTypes, EndpointPathResolver.useEndpointId());
parameterMapper, endpointMediaTypes,
EndpointPathResolver.useEndpointId(), null, null);
}
@Bean
......
......@@ -18,18 +18,20 @@ package org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.endpoint.EndpointInfo;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
import org.springframework.boot.actuate.endpoint.web.WebEndpointOperation;
import org.springframework.boot.actuate.endpoint.web.WebOperation;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
......@@ -190,16 +192,17 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests {
}
@Test
public void allEndpointsAvailableUnderCloudFoundryWithoutEnablingWeb()
public void allEndpointsAvailableUnderCloudFoundryWithoutEnablingWebInclues()
throws Exception {
setupContextWithCloudEnabled();
this.context.register(TestConfiguration.class);
this.context.refresh();
CloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping();
List<EndpointInfo<WebEndpointOperation>> endpoints = (List<EndpointInfo<WebEndpointOperation>>) handlerMapping
List<EndpointInfo<WebOperation>> endpoints = (List<EndpointInfo<WebOperation>>) handlerMapping
.getEndpoints();
assertThat(endpoints.size()).isEqualTo(1);
assertThat(endpoints.get(0).getId()).isEqualTo("test");
List<String> endpointIds = endpoints.stream().map(EndpointInfo::getId)
.collect(Collectors.toList());
assertThat(endpointIds).contains("test");
}
@Test
......@@ -208,12 +211,14 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests {
this.context.register(TestConfiguration.class);
this.context.refresh();
CloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping();
List<EndpointInfo<WebEndpointOperation>> endpoints = (List<EndpointInfo<WebEndpointOperation>>) handlerMapping
List<EndpointInfo<WebOperation>> endpoints = (List<EndpointInfo<WebOperation>>) handlerMapping
.getEndpoints();
assertThat(endpoints.size()).isEqualTo(1);
assertThat(endpoints.get(0).getOperations()).hasSize(1);
assertThat(endpoints.get(0).getOperations().iterator().next()
.getRequestPredicate().getPath()).isEqualTo("test");
EndpointInfo<WebOperation> endpoint = endpoints.stream()
.filter((candidate) -> "test".equals(candidate.getId())).findFirst()
.get();
assertThat(endpoint.getOperations()).hasSize(1);
WebOperation operation = endpoint.getOperations().iterator().next();
assertThat(operation.getRequestPredicate().getPath()).isEqualTo("test");
}
private void setupContextWithCloudEnabled() {
......@@ -231,6 +236,7 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests {
PropertyPlaceholderAutoConfiguration.class,
WebClientCustomizerConfig.class, WebClientAutoConfiguration.class,
ManagementContextAutoConfiguration.class, EndpointAutoConfiguration.class,
WebEndpointAutoConfiguration.class,
ReactiveCloudFoundryActuatorAutoConfiguration.class);
}
......
......@@ -17,6 +17,7 @@
package org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.junit.After;
......@@ -24,13 +25,14 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
import org.springframework.boot.actuate.endpoint.EndpointInfo;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
import org.springframework.boot.actuate.endpoint.web.WebEndpointOperation;
import org.springframework.boot.actuate.endpoint.web.WebOperation;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
......@@ -79,7 +81,7 @@ public class CloudFoundryActuatorAutoConfigurationTests {
RestTemplateAutoConfiguration.class,
ManagementContextAutoConfiguration.class,
ServletManagementContextAutoConfiguration.class,
EndpointAutoConfiguration.class,
EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,
CloudFoundryActuatorAutoConfiguration.class);
}
......@@ -208,30 +210,34 @@ public class CloudFoundryActuatorAutoConfigurationTests {
}
@Test
public void allEndpointsAvailableUnderCloudFoundryWithoutEnablingWeb()
public void allEndpointsAvailableUnderCloudFoundryWithoutExposeAllOnWeb()
throws Exception {
this.context.register(TestConfiguration.class);
this.context.refresh();
CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping();
List<EndpointInfo<WebEndpointOperation>> endpoints = (List<EndpointInfo<WebEndpointOperation>>) handlerMapping
List<EndpointInfo<WebOperation>> endpoints = (List<EndpointInfo<WebOperation>>) handlerMapping
.getEndpoints();
assertThat(endpoints.size()).isEqualTo(1);
assertThat(endpoints.get(0).getId()).isEqualTo("test");
assertThat(endpoints.stream()
.filter((candidate) -> "test".equals(candidate.getId())).findFirst())
.isNotEmpty();
}
@Test
public void endpointPathCustomizationIsNotApplied() throws Exception {
TestPropertyValues.of("endpoints.test.web.path=another/custom")
TestPropertyValues.of("management.endpoints.web.path-mapping.test=custom")
.applyTo(this.context);
this.context.register(TestConfiguration.class);
this.context.refresh();
CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping();
List<EndpointInfo<WebEndpointOperation>> endpoints = (List<EndpointInfo<WebEndpointOperation>>) handlerMapping
List<EndpointInfo<WebOperation>> endpoints = (List<EndpointInfo<WebOperation>>) handlerMapping
.getEndpoints();
assertThat(endpoints.size()).isEqualTo(1);
assertThat(endpoints.get(0).getOperations()).hasSize(1);
assertThat(endpoints.get(0).getOperations().iterator().next()
.getRequestPredicate().getPath()).isEqualTo("test");
EndpointInfo<WebOperation> endpoint = endpoints.stream()
.filter((candidate) -> "test".equals(candidate.getId())).findFirst()
.get();
Collection<WebOperation> operations = endpoint.getOperations();
assertThat(operations).hasSize(1);
assertThat(operations.iterator().next().getRequestPredicate().getPath())
.isEqualTo("test");
}
private CloudFoundryWebEndpointServletHandlerMapping getHandlerMapping() {
......
......@@ -27,15 +27,16 @@ import org.junit.Test;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.AccessLevel;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryAuthorizationException;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryAuthorizationException.Reason;
import org.springframework.boot.actuate.endpoint.ParameterMapper;
import org.springframework.boot.actuate.endpoint.EndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.boot.actuate.endpoint.cache.CachingConfiguration;
import org.springframework.boot.actuate.endpoint.convert.ConversionServiceParameterMapper;
import org.springframework.boot.actuate.endpoint.reflect.ParameterMapper;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.EndpointPathResolver;
import org.springframework.boot.actuate.endpoint.web.WebOperation;
import org.springframework.boot.actuate.endpoint.web.annotation.WebAnnotationEndpointDiscoverer;
import org.springframework.boot.endpoint.web.EndpointMapping;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
......@@ -203,7 +204,7 @@ public class CloudFoundryMvcWebEndpointIntegrationTests {
@Bean
public CloudFoundryWebEndpointServletHandlerMapping cloudFoundryWebEndpointServletHandlerMapping(
WebAnnotationEndpointDiscoverer webEndpointDiscoverer,
EndpointDiscoverer<WebOperation> webEndpointDiscoverer,
EndpointMediaTypes endpointMediaTypes,
CloudFoundrySecurityInterceptor interceptor) {
CorsConfiguration corsConfiguration = new CorsConfiguration();
......@@ -222,8 +223,8 @@ public class CloudFoundryMvcWebEndpointIntegrationTests {
ParameterMapper parameterMapper = new ConversionServiceParameterMapper(
DefaultConversionService.getSharedInstance());
return new WebAnnotationEndpointDiscoverer(applicationContext,
parameterMapper, (id) -> new CachingConfiguration(0),
endpointMediaTypes, EndpointPathResolver.useEndpointId());
parameterMapper, endpointMediaTypes,
EndpointPathResolver.useEndpointId(), null, null);
}
@Bean
......
......@@ -43,7 +43,8 @@ public class ConditionsReportEndpointAutoConfigurationTests {
@Test
public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean()
throws Exception {
this.contextRunner.withPropertyValues("endpoints.conditions.enabled:false")
this.contextRunner
.withPropertyValues("management.endpoint.conditions.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(ConditionsReportEndpoint.class));
}
......
......@@ -37,15 +37,18 @@ public class ShutdownEndpointAutoConfigurationTests {
@Test
public void runShouldHaveEndpointBean() {
this.contextRunner.withPropertyValues("endpoints.shutdown.enabled:true").run(
(context) -> assertThat(context).hasSingleBean(ShutdownEndpoint.class));
this.contextRunner.withPropertyValues("management.endpoint.shutdown.enabled:true")
.run((context) -> assertThat(context)
.hasSingleBean(ShutdownEndpoint.class));
}
@Test
public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean()
throws Exception {
this.contextRunner.withPropertyValues("endpoints.shutdown.enabled:false").run(
(context) -> assertThat(context).doesNotHaveBean(ShutdownEndpoint.class));
this.contextRunner
.withPropertyValues("management.endpoint.shutdown.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(ShutdownEndpoint.class));
}
}
......@@ -53,7 +53,8 @@ public class ConfigurationPropertiesReportEndpointAutoConfigurationTests {
@Test
public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean()
throws Exception {
this.contextRunner.withPropertyValues("endpoints.configprops.enabled:false")
this.contextRunner
.withPropertyValues("management.endpoint.configprops.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(ConfigurationPropertiesReportEndpoint.class));
}
......@@ -62,7 +63,7 @@ public class ConfigurationPropertiesReportEndpointAutoConfigurationTests {
public void keysToSanitizeCanBeConfiguredViaTheEnvironment() throws Exception {
this.contextRunner.withUserConfiguration(Config.class)
.withPropertyValues(
"endpoints.configprops.keys-to-sanitize: .*pass.*, property")
"management.endpoint.configprops.keys-to-sanitize: .*pass.*, property")
.run(validateTestProperties("******", "******"));
}
......
/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.endpoint;
import org.junit.Test;
import org.springframework.boot.actuate.endpoint.DefaultEnablement;
import org.springframework.boot.actuate.endpoint.EndpointExposure;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.util.ObjectUtils;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link EndpointEnablementProvider}.
*
* @author Stephane Nicoll
*/
public class EndpointEnablementProviderTests {
@Test
public void defaultEnablementDisabled() {
EndpointEnablement enablement = getEndpointEnablement("foo",
DefaultEnablement.DISABLED);
validate(enablement, false, "endpoint 'foo' is disabled by default");
}
@Test
public void defaultEnablementDisabledWithGeneralEnablement() {
EndpointEnablement enablement = getEndpointEnablement("foo",
DefaultEnablement.DISABLED, "endpoints.default.enabled=true");
validate(enablement, false, "endpoint 'foo' is disabled by default");
}
@Test
public void defaultEnablementDisabledWithGeneralTechEnablement() {
EndpointEnablement enablement = getEndpointEnablement("foo",
DefaultEnablement.DISABLED, EndpointExposure.WEB,
"endpoints.default.web.enabled=true");
validate(enablement, false, "endpoint 'foo' (web) is disabled by default");
}
@Test
public void defaultEnablementDisabledWithOverride() {
EndpointEnablement enablement = getEndpointEnablement("foo",
DefaultEnablement.DISABLED, "endpoints.foo.enabled=true");
validate(enablement, true, "found property endpoints.foo.enabled");
}
@Test
public void defaultEnablementDisabledWithTechOverride() {
EndpointEnablement enablement = getEndpointEnablement("foo",
DefaultEnablement.DISABLED, EndpointExposure.WEB,
"endpoints.foo.web.enabled=true");
validate(enablement, true, "found property endpoints.foo.web.enabled");
}
@Test
public void defaultEnablementDisabledWithIrrelevantTechOverride() {
EndpointEnablement enablement = getEndpointEnablement("foo",
DefaultEnablement.DISABLED, EndpointExposure.WEB,
"endpoints.foo.jmx.enabled=true");
validate(enablement, false, "endpoint 'foo' (web) is disabled by default");
}
@Test
public void defaultEnablementEnabled() {
EndpointEnablement enablement = getEndpointEnablement("bar",
DefaultEnablement.ENABLED);
validate(enablement, true, "endpoint 'bar' is enabled by default");
}
@Test
public void defaultEnablementEnabledWithGeneralDisablement() {
EndpointEnablement enablement = getEndpointEnablement("bar",
DefaultEnablement.ENABLED, "endpoints.default.enabled=false");
validate(enablement, true, "endpoint 'bar' is enabled by default");
}
@Test
public void defaultEnablementEnabledWithGeneralTechDisablement() {
EndpointEnablement enablement = getEndpointEnablement("bar",
DefaultEnablement.ENABLED, EndpointExposure.JMX,
"endpoints.default.jmx.enabled=false");
validate(enablement, true, "endpoint 'bar' (jmx) is enabled by default");
}
@Test
public void defaultEnablementEnabledWithOverride() {
EndpointEnablement enablement = getEndpointEnablement("bar",
DefaultEnablement.ENABLED, "endpoints.bar.enabled=false");
validate(enablement, false, "found property endpoints.bar.enabled");
}
@Test
public void defaultEnablementEnabledWithTechOverride() {
EndpointEnablement enablement = getEndpointEnablement("bar",
DefaultEnablement.ENABLED, EndpointExposure.JMX,
"endpoints.bar.jmx.enabled=false");
validate(enablement, false, "found property endpoints.bar.jmx.enabled");
}
@Test
public void defaultEnablementEnabledWithIrrelevantTechOverride() {
EndpointEnablement enablement = getEndpointEnablement("bar",
DefaultEnablement.ENABLED, EndpointExposure.JMX,
"endpoints.bar.web.enabled=false");
validate(enablement, true, "endpoint 'bar' (jmx) is enabled by default");
}
@Test
public void defaultEnablementNeutral() {
EndpointEnablement enablement = getEndpointEnablement("biz",
DefaultEnablement.NEUTRAL);
validate(enablement, true, "endpoint 'biz' is enabled (default)");
}
@Test
public void defaultEnablementNeutralWeb() {
EndpointEnablement enablement = getEndpointEnablement("biz",
DefaultEnablement.NEUTRAL, EndpointExposure.WEB);
validate(enablement, false, "endpoint 'default' (web) is disabled by default");
}
@Test
public void defaultEnablementNeutralJmx() {
EndpointEnablement enablement = getEndpointEnablement("biz",
DefaultEnablement.NEUTRAL, EndpointExposure.JMX);
validate(enablement, true,
"endpoint 'biz' (jmx) is enabled (default for jmx endpoints)");
}
@Test
public void defaultEnablementNeutralWithGeneralDisablement() {
EndpointEnablement enablement = getEndpointEnablement("biz",
DefaultEnablement.NEUTRAL, "endpoints.default.enabled=false");
validate(enablement, false, "found property endpoints.default.enabled");
}
@Test
public void defaultEnablementNeutralJmxWithTechDisablement() {
EndpointEnablement enablement = getEndpointEnablement("biz",
DefaultEnablement.NEUTRAL, EndpointExposure.JMX,
"endpoints.default.jmx.enabled=false");
validate(enablement, false, "found property endpoints.default.jmx.enabled");
}
@Test
public void defaultEnablementNeutralTechTakesPrecedence() {
EndpointEnablement enablement = getEndpointEnablement("biz",
DefaultEnablement.NEUTRAL, EndpointExposure.JMX,
"endpoints.default.enabled=true", "endpoints.default.jmx.enabled=false");
validate(enablement, false, "found property endpoints.default.jmx.enabled");
}
@Test
public void defaultEnablementNeutralWebWithTechEnablement() {
EndpointEnablement enablement = getEndpointEnablement("biz",
DefaultEnablement.NEUTRAL, EndpointExposure.WEB,
"endpoints.default.web.enabled=true");
validate(enablement, true, "found property endpoints.default.web.enabled");
}
@Test
public void defaultEnablementNeutralJmxWithUnrelatedTechDisablement() {
EndpointEnablement enablement = getEndpointEnablement("biz",
DefaultEnablement.NEUTRAL, EndpointExposure.JMX,
"endpoints.default.web.enabled=false");
validate(enablement, true,
"endpoint 'biz' (jmx) is enabled (default for jmx endpoints)");
}
@Test
public void defaultEnablementNeutralWithOverride() {
EndpointEnablement enablement = getEndpointEnablement("biz",
DefaultEnablement.NEUTRAL, "endpoints.biz.enabled=false");
validate(enablement, false, "found property endpoints.biz.enabled");
}
@Test
public void defaultEnablementNeutralWebWithOverride() {
EndpointEnablement enablement = getEndpointEnablement("biz",
DefaultEnablement.NEUTRAL, EndpointExposure.WEB,
"endpoints.biz.web.enabled=true");
validate(enablement, true, "found property endpoints.biz.web.enabled");
}
@Test
public void defaultEnablementNeutralJmxWithOverride() {
EndpointEnablement enablement = getEndpointEnablement("biz",
DefaultEnablement.NEUTRAL, EndpointExposure.JMX,
"endpoints.biz.jmx.enabled=false");
validate(enablement, false, "found property endpoints.biz.jmx.enabled");
}
@Test
public void defaultEnablementNeutralTechTakesPrecedenceOnEverything() {
EndpointEnablement enablement = getEndpointEnablement("biz",
DefaultEnablement.NEUTRAL, EndpointExposure.JMX,
"endpoints.default.enabled=false", "endpoints.default.jmx.enabled=false",
"endpoints.biz.enabled=false", "endpoints.biz.jmx.enabled=true");
validate(enablement, true, "found property endpoints.biz.jmx.enabled");
}
@Test
public void defaultEnablementNeutralSpecificTakesPrecedenceOnDefaults() {
EndpointEnablement enablement = getEndpointEnablement("biz",
DefaultEnablement.NEUTRAL, EndpointExposure.JMX,
"endpoints.default.enabled=false", "endpoints.default.jmx.enabled=false",
"endpoints.biz.enabled=true");
validate(enablement, true, "found property endpoints.biz.enabled");
}
@Test
public void defaultEnablementNeutralDefaultTechTakesPrecedenceOnGeneralDefault() {
EndpointEnablement enablement = getEndpointEnablement("biz",
DefaultEnablement.NEUTRAL, EndpointExposure.JMX,
"endpoints.default.enabled=false", "endpoints.default.jmx.enabled=true");
validate(enablement, true, "found property endpoints.default.jmx.enabled");
}
private EndpointEnablement getEndpointEnablement(String id,
DefaultEnablement defaultEnablement, String... environment) {
return getEndpointEnablement(id, defaultEnablement, null, environment);
}
private EndpointEnablement getEndpointEnablement(String id,
DefaultEnablement defaultEnablement, EndpointExposure exposure,
String... environment) {
MockEnvironment env = new MockEnvironment();
TestPropertyValues.of(environment).applyTo(env);
EndpointEnablementProvider provider = new EndpointEnablementProvider(env);
if (exposure != null) {
return provider.getEndpointEnablement(id, defaultEnablement, exposure);
}
return provider.getEndpointEnablement(id, defaultEnablement);
}
private void validate(EndpointEnablement enablement, boolean enabled,
String... messages) {
assertThat(enablement).isNotNull();
assertThat(enablement.isEnabled()).isEqualTo(enabled);
if (!ObjectUtils.isEmpty(messages)) {
assertThat(enablement.getReason()).contains(messages);
}
}
}
......@@ -16,39 +16,39 @@
package org.springframework.boot.actuate.autoconfigure.endpoint;
import java.util.function.Function;
import org.junit.Test;
import org.springframework.boot.actuate.endpoint.cache.CachingConfiguration;
import org.springframework.boot.actuate.endpoint.cache.CachingConfigurationFactory;
import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link DefaultCachingConfigurationFactory}.
* Tests for {@link EndpointIdTimeToLivePropertyFunction}.
*
* @author Stephane Nicoll
* @author Phillip Webb
*/
public class DefaultCachingConfigurationFactoryTests {
public class EndpointIdTimeToLivePropertyFunctionTests {
private final MockEnvironment environment = new MockEnvironment();
private final CachingConfigurationFactory factory = new DefaultCachingConfigurationFactory(
private final Function<String, Long> timeToLive = new EndpointIdTimeToLivePropertyFunction(
this.environment);
@Test
public void defaultConfiguration() {
CachingConfiguration configuration = this.factory.getCachingConfiguration("test");
assertThat(configuration).isNotNull();
assertThat(configuration.getTimeToLive()).isEqualTo(0);
Long result = this.timeToLive.apply("test");
assertThat(result).isNull();
}
@Test
public void userConfiguration() {
this.environment.setProperty("endpoints.test.cache.time-to-live", "500");
CachingConfiguration configuration = this.factory.getCachingConfiguration("test");
assertThat(configuration).isNotNull();
assertThat(configuration.getTimeToLive()).isEqualTo(500);
this.environment.setProperty("management.endpoint.test.cache.time-to-live",
"500");
Long result = this.timeToLive.apply("test");
assertThat(result).isEqualTo(500L);
}
}
/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.endpoint;
import java.util.Collections;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.actuate.endpoint.EndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.EndpointFilter;
import org.springframework.boot.actuate.endpoint.EndpointInfo;
import org.springframework.boot.actuate.endpoint.Operation;
import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ExposeExcludePropertyEndpointFilter}.
*
* @author Phillip Webb
*/
public class ExposeExcludePropertyEndpointFilterTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
private MockEnvironment environment = new MockEnvironment();
private EndpointFilter<Operation> filter;
@Mock
private TestEndpointDiscoverer discoverer;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Test
public void createWhenDiscovererTypeIsNullShouldThrowException() throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Discoverer Type must not be null");
new ExposeExcludePropertyEndpointFilter<>(null, this.environment, "foo");
}
@Test
public void createWhenEnvironmentIsNullShouldThrowException() throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Environment must not be null");
new ExposeExcludePropertyEndpointFilter<>(TestEndpointDiscoverer.class, null,
"foo");
}
@Test
public void createWhenPrefixIsNullShouldThrowException() throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Prefix must not be empty");
new ExposeExcludePropertyEndpointFilter<Operation>(TestEndpointDiscoverer.class,
this.environment, null);
}
@Test
public void createWhenPrefixIsEmptyShouldThrowException() throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Prefix must not be empty");
new ExposeExcludePropertyEndpointFilter<Operation>(TestEndpointDiscoverer.class,
this.environment, "");
}
@Test
public void matchWhenExposeIsEmptyAndExcludeIsEmptyAndInDefaultShouldMatch()
throws Exception {
setupFilter("", "");
assertThat(match("def")).isTrue();
}
@Test
public void matchWhenExposeIsEmptyAndExcludeIsEmptyAndNotInDefaultShouldNotMatch()
throws Exception {
setupFilter("", "");
assertThat(match("bar")).isFalse();
}
@Test
public void matchWhenExposeMatchesAndExcludeIsEmptyShouldMatch() throws Exception {
setupFilter("bar", "");
assertThat(match("bar")).isTrue();
}
@Test
public void matchWhenExposeDoesNotMatchAndExcludeIsEmptyShouldNotMatch()
throws Exception {
setupFilter("bar", "");
assertThat(match("baz")).isFalse();
}
@Test
public void matchWhenExposeMatchesAndExcludeMatchesShouldNotMatch() throws Exception {
setupFilter("bar,baz", "baz");
assertThat(match("baz")).isFalse();
}
@Test
public void matchWhenExposeMatchesAndExcludeDoesNotMatchShouldMatch()
throws Exception {
setupFilter("bar,baz", "buz");
assertThat(match("baz")).isTrue();
}
@Test
public void matchWhenExposeMatchesWithDifferentCaseShouldMatch() throws Exception {
setupFilter("bar", "");
assertThat(match("bAr")).isTrue();
}
@Test
public void matchWhenDicovererDoesNotMatchShouldMatch() throws Exception {
this.environment.setProperty("foo.expose", "bar");
this.environment.setProperty("foo.exclude", "");
this.filter = new ExposeExcludePropertyEndpointFilter<>(
DifferentTestEndpointDiscoverer.class, this.environment, "foo");
assertThat(match("baz")).isTrue();
}
@Test
public void matchWhenIncludeIsAsteriskShouldMatchAll() throws Exception {
setupFilter("*", "buz");
assertThat(match("bar")).isTrue();
assertThat(match("baz")).isTrue();
assertThat(match("buz")).isFalse();
}
@Test
public void matchWhenExcludeIsAsteriskShouldMatchNone() throws Exception {
setupFilter("bar,baz,buz", "*");
assertThat(match("bar")).isFalse();
assertThat(match("baz")).isFalse();
assertThat(match("buz")).isFalse();
}
private void setupFilter(String expose, String exclude) {
this.environment.setProperty("foo.expose", expose);
this.environment.setProperty("foo.exclude", exclude);
this.filter = new ExposeExcludePropertyEndpointFilter<>(
TestEndpointDiscoverer.class, this.environment, "foo", "def");
}
private boolean match(String id) {
EndpointInfo<Operation> info = new EndpointInfo<>(id, true,
Collections.emptyList());
return this.filter.match(info, this.discoverer);
}
private abstract static class TestEndpointDiscoverer
implements EndpointDiscoverer<Operation> {
}
private abstract static class DifferentTestEndpointDiscoverer
implements EndpointDiscoverer<Operation> {
}
}
......@@ -41,7 +41,7 @@ public class DefaultEndpointObjectNameFactoryTests {
private final MockEnvironment environment = new MockEnvironment();
private final JmxEndpointExporterProperties properties = new JmxEndpointExporterProperties(
private final JmxEndpointProperties properties = new JmxEndpointProperties(
this.environment);
private final MBeanServer mBeanServer = mock(MBeanServer.class);
......
......@@ -25,10 +25,9 @@ import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointProvider;
import org.springframework.boot.actuate.endpoint.DefaultEnablement;
import org.springframework.boot.actuate.endpoint.EndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.EndpointInfo;
import org.springframework.boot.actuate.endpoint.web.WebEndpointOperation;
import org.springframework.boot.actuate.endpoint.web.WebOperation;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
......@@ -41,7 +40,7 @@ import static org.mockito.BDDMockito.given;
public class DefaultEndpointPathProviderTests {
@Mock
private EndpointProvider<WebEndpointOperation> endpointProvider;
private EndpointDiscoverer<WebOperation> discoverer;
@Before
public void setup() {
......@@ -81,16 +80,13 @@ public class DefaultEndpointPathProviderTests {
}
private DefaultEndpointPathProvider createProvider(String contextPath) {
Collection<EndpointInfo<WebEndpointOperation>> endpoints = new ArrayList<>();
endpoints.add(new EndpointInfo<>("foo", DefaultEnablement.ENABLED,
Collections.emptyList()));
endpoints.add(new EndpointInfo<>("bar", DefaultEnablement.ENABLED,
Collections.emptyList()));
given(this.endpointProvider.getEndpoints()).willReturn(endpoints);
Collection<EndpointInfo<WebOperation>> endpoints = new ArrayList<>();
endpoints.add(new EndpointInfo<>("foo", true, Collections.emptyList()));
endpoints.add(new EndpointInfo<>("bar", true, Collections.emptyList()));
given(this.discoverer.discoverEndpoints()).willReturn(endpoints);
WebEndpointProperties webEndpointProperties = new WebEndpointProperties();
webEndpointProperties.setBasePath(contextPath);
return new DefaultEndpointPathProvider(this.endpointProvider,
webEndpointProperties);
return new DefaultEndpointPathProvider(this.discoverer, webEndpointProperties);
}
}
......@@ -14,12 +14,13 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.endpoint;
package org.springframework.boot.actuate.autoconfigure.endpoint.web;
import java.util.Collections;
import org.junit.Test;
import org.springframework.boot.actuate.endpoint.web.EndpointPathResolver;
import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
......@@ -30,20 +31,18 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class DefaultEndpointPathResolverTests {
private final MockEnvironment environment = new MockEnvironment();
private final EndpointPathResolver resolver = new DefaultEndpointPathResolver(
this.environment);
@Test
public void defaultConfiguration() {
assertThat(this.resolver.resolvePath("test")).isEqualTo("test");
EndpointPathResolver resolver = new DefaultEndpointPathResolver(
Collections.emptyMap());
assertThat(resolver.resolvePath("test")).isEqualTo("test");
}
@Test
public void userConfiguration() {
this.environment.setProperty("endpoints.test.web.path", "custom");
assertThat(this.resolver.resolvePath("test")).isEqualTo("custom");
EndpointPathResolver resolver = new DefaultEndpointPathResolver(
Collections.singletonMap("test", "custom"));
assertThat(resolver.resolvePath("test")).isEqualTo("custom");
}
}
......@@ -14,10 +14,11 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.endpoint;
package org.springframework.boot.actuate.autoconfigure.endpoint.web;
import org.junit.Test;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.autoconfigure.AutoConfigurations;
......@@ -26,16 +27,16 @@ import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link EndpointAutoConfiguration}.
* Tests for {@link WebEndpointAutoConfiguration}.
*
* @author Andy Wilkinson
*/
public class EndpointAutoConfigurationTests {
public class WebEndpointAutoConfigurationTests {
@Test
public void webApplicationConfiguresEndpointMediaTypes() {
new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(EndpointAutoConfiguration.class))
new WebApplicationContextRunner().withConfiguration(AutoConfigurations
.of(EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class))
.run((context) -> {
EndpointMediaTypes endpointMediaTypes = context
.getBean(EndpointMediaTypes.class);
......
......@@ -51,7 +51,7 @@ public class EnvironmentEndpointAutoConfigurationTests {
@Test
public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean()
throws Exception {
this.contextRunner.withPropertyValues("endpoints.env.enabled:false")
this.contextRunner.withPropertyValues("management.endpoint.env.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(EnvironmentEndpoint.class));
}
......@@ -59,7 +59,7 @@ public class EnvironmentEndpointAutoConfigurationTests {
@Test
public void keysToSanitizeCanBeConfiguredViaTheEnvironment() throws Exception {
this.contextRunner.withSystemProperties("dbPassword=123456", "apiKey=123456")
.withPropertyValues("endpoints.env.keys-to-sanitize=.*pass.*")
.withPropertyValues("management.endpoint.env.keys-to-sanitize=.*pass.*")
.run(validateSystemProperties("******", "123456"));
}
......
......@@ -49,8 +49,9 @@ public class FlywayEndpointAutoConfigurationTests {
@Test
public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean()
throws Exception {
this.contextRunner.withPropertyValues("endpoints.flyway.enabled:false").run(
(context) -> assertThat(context).doesNotHaveBean(FlywayEndpoint.class));
this.contextRunner.withPropertyValues("management.endpoint.flyway.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(FlywayEndpoint.class));
}
@Configuration
......
......@@ -84,15 +84,18 @@ public class HealthEndpointAutoConfigurationTests {
@Test
public void runShouldHaveStatusEndpointBeanEvenIfDefaultIsDisabled() {
this.contextRunner.withPropertyValues("endpoints.default.enabled:false").run(
(context) -> assertThat(context).hasSingleBean(StatusEndpoint.class));
// FIXME
this.contextRunner.withPropertyValues("management.endpoint.default.enabled:false")
.run((context) -> assertThat(context)
.hasSingleBean(StatusEndpoint.class));
}
@Test
public void runWhenEnabledPropertyIsFalseShouldNotHaveStatusEndpointBean()
throws Exception {
this.contextRunner.withPropertyValues("endpoints.status.enabled:false").run(
(context) -> assertThat(context).doesNotHaveBean(StatusEndpoint.class));
this.contextRunner.withPropertyValues("management.endpoint.status.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(StatusEndpoint.class));
}
@Configuration
......
......@@ -20,9 +20,9 @@ import java.util.Map;
import org.junit.Test;
import org.springframework.boot.actuate.health.HealthReactiveWebEndpointExtension;
import org.springframework.boot.actuate.health.HealthStatusHttpMapper;
import org.springframework.boot.actuate.health.StatusReactiveWebEndpointExtension;
import org.springframework.boot.actuate.health.ReactiveHealthEndpointWebExtension;
import org.springframework.boot.actuate.health.ReactiveStatusEndpointWebExtension;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.test.util.ReflectionTestUtils;
......@@ -46,33 +46,34 @@ public class HealthWebEndpointReactiveManagementContextConfigurationTests {
@Test
public void runShouldCreateExtensionBeans() throws Exception {
this.contextRunner.run((context) -> assertThat(context)
.hasSingleBean(StatusReactiveWebEndpointExtension.class)
.hasSingleBean(HealthReactiveWebEndpointExtension.class));
.hasSingleBean(ReactiveStatusEndpointWebExtension.class)
.hasSingleBean(ReactiveHealthEndpointWebExtension.class));
}
@Test
public void runWhenHealthEndpointIsDisabledShouldNotCreateExtensionBeans()
throws Exception {
this.contextRunner.withPropertyValues("endpoints.health.enabled:false")
this.contextRunner.withPropertyValues("management.endpoint.health.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(HealthReactiveWebEndpointExtension.class));
.doesNotHaveBean(ReactiveHealthEndpointWebExtension.class));
}
@Test
public void runWhenStatusEndpointIsDisabledShouldNotCreateExtensionBeans()
throws Exception {
this.contextRunner.withPropertyValues("endpoints.status.enabled:false")
this.contextRunner.withPropertyValues("management.endpoint.status.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(StatusReactiveWebEndpointExtension.class));
.doesNotHaveBean(ReactiveStatusEndpointWebExtension.class));
}
@Test
public void runWithCustomHealthMappingShouldMapStatusCode() throws Exception {
this.contextRunner
.withPropertyValues("management.health.status.http-mapping.CUSTOM=500")
.withPropertyValues(
"management.health.status.http-mapping.CUSTOM=500")
.run((context) -> {
Object extension = context
.getBean(HealthReactiveWebEndpointExtension.class);
.getBean(ReactiveHealthEndpointWebExtension.class);
HealthStatusHttpMapper mapper = (HealthStatusHttpMapper) ReflectionTestUtils
.getField(extension, "statusHttpMapper");
Map<String, Integer> statusMappings = mapper.getStatusMapping();
......@@ -85,10 +86,11 @@ public class HealthWebEndpointReactiveManagementContextConfigurationTests {
@Test
public void runWithCustomStatusMappingShouldMapStatusCode() throws Exception {
this.contextRunner
.withPropertyValues("management.health.status.http-mapping.CUSTOM=500")
.withPropertyValues(
"management.health.status.http-mapping.CUSTOM=500")
.run((context) -> {
Object extension = context
.getBean(StatusReactiveWebEndpointExtension.class);
.getBean(ReactiveStatusEndpointWebExtension.class);
HealthStatusHttpMapper mapper = (HealthStatusHttpMapper) ReflectionTestUtils
.getField(extension, "statusHttpMapper");
Map<String, Integer> statusMappings = mapper.getStatusMapping();
......
......@@ -20,9 +20,9 @@ import java.util.Map;
import org.junit.Test;
import org.springframework.boot.actuate.health.HealthEndpointWebExtension;
import org.springframework.boot.actuate.health.HealthStatusHttpMapper;
import org.springframework.boot.actuate.health.HealthWebEndpointExtension;
import org.springframework.boot.actuate.health.StatusWebEndpointExtension;
import org.springframework.boot.actuate.health.StatusEndpointWebExtension;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.test.util.ReflectionTestUtils;
......@@ -46,24 +46,24 @@ public class HealthWebEndpointServletManagementContextConfigurationTests {
@Test
public void runShouldCreateExtensionBeans() throws Exception {
this.contextRunner.run((context) -> assertThat(context)
.hasSingleBean(StatusWebEndpointExtension.class)
.hasSingleBean(HealthWebEndpointExtension.class));
.hasSingleBean(StatusEndpointWebExtension.class)
.hasSingleBean(HealthEndpointWebExtension.class));
}
@Test
public void runWhenHealthEndpointIsDisabledShouldNotCreateExtensionBeans()
throws Exception {
this.contextRunner.withPropertyValues("endpoints.health.enabled:false")
this.contextRunner.withPropertyValues("management.endpoint.health.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(HealthWebEndpointExtension.class));
.doesNotHaveBean(HealthEndpointWebExtension.class));
}
@Test
public void runWhenStatusEndpointIsDisabledShouldNotCreateExtensionBeans()
throws Exception {
this.contextRunner.withPropertyValues("endpoints.status.enabled:false")
this.contextRunner.withPropertyValues("management.endpoint.status.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(StatusWebEndpointExtension.class));
.doesNotHaveBean(StatusEndpointWebExtension.class));
}
@Test
......@@ -71,7 +71,7 @@ public class HealthWebEndpointServletManagementContextConfigurationTests {
this.contextRunner
.withPropertyValues("management.health.status.http-mapping.CUSTOM=500")
.run((context) -> {
Object extension = context.getBean(HealthWebEndpointExtension.class);
Object extension = context.getBean(HealthEndpointWebExtension.class);
HealthStatusHttpMapper mapper = (HealthStatusHttpMapper) ReflectionTestUtils
.getField(extension, "statusHttpMapper");
Map<String, Integer> statusMappings = mapper.getStatusMapping();
......@@ -86,7 +86,7 @@ public class HealthWebEndpointServletManagementContextConfigurationTests {
this.contextRunner
.withPropertyValues("management.health.status.http-mapping.CUSTOM=500")
.run((context) -> {
Object extension = context.getBean(StatusWebEndpointExtension.class);
Object extension = context.getBean(StatusEndpointWebExtension.class);
HealthStatusHttpMapper mapper = (HealthStatusHttpMapper) ReflectionTestUtils
.getField(extension, "statusHttpMapper");
Map<String, Integer> statusMappings = mapper.getStatusMapping();
......
......@@ -37,21 +37,23 @@ public class InfoEndpointAutoConfigurationTests {
@Test
public void runShouldHaveEndpointBean() {
this.contextRunner.withPropertyValues("endpoints.shutdown.enabled:true")
this.contextRunner.withPropertyValues("management.endpoint.shutdown.enabled:true")
.run((context) -> assertThat(context).hasSingleBean(InfoEndpoint.class));
}
@Test
public void runShouldHaveEndpointBeanEvenIfDefaultIsDisabled() {
this.contextRunner.withPropertyValues("endpoints.default.enabled:false")
// FIXME
this.contextRunner.withPropertyValues("management.endpoint.default.enabled:false")
.run((context) -> assertThat(context).hasSingleBean(InfoEndpoint.class));
}
@Test
public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean()
throws Exception {
this.contextRunner.withPropertyValues("endpoints.info.enabled:false").run(
(context) -> assertThat(context).doesNotHaveBean(InfoEndpoint.class));
this.contextRunner.withPropertyValues("management.endpoint.info.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(InfoEndpoint.class));
}
}
......@@ -61,8 +61,8 @@ public class JmxEndpointIntegrationTests {
}
@Test
public void jmxEndpointsCanBeDisabled() {
this.contextRunner.withPropertyValues("endpoints.default.jmx.enabled:false")
public void jmxEndpointsCanBeExcluded() {
this.contextRunner.withPropertyValues("management.endpoints.jmx.exclude:*")
.run((context) -> {
MBeanServer mBeanServer = context.getBean(MBeanServer.class);
checkEndpointMBeans(mBeanServer, new String[0],
......@@ -74,9 +74,9 @@ public class JmxEndpointIntegrationTests {
}
@Test
public void singleJmxEndpointCanBeEnabled() {
this.contextRunner.withPropertyValues("endpoints.default.jmx.enabled=false",
"endpoints.beans.jmx.enabled=true").run((context) -> {
public void singleJmxEndpointCanBeExposed() {
this.contextRunner.withPropertyValues("management.endpoints.jmx.expose=beans")
.run((context) -> {
MBeanServer mBeanServer = context.getBean(MBeanServer.class);
checkEndpointMBeans(mBeanServer, new String[] { "beans" },
new String[] { "conditions", "configprops", "env", "health",
......
......@@ -27,6 +27,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.jolokia.JolokiaManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
......@@ -103,6 +104,7 @@ public class JolokiaManagementContextConfigurationIntegrationTests {
@MinimalWebConfiguration
@Import({ JacksonAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, EndpointAutoConfiguration.class,
WebEndpointAutoConfiguration.class,
ServletManagementContextAutoConfiguration.class,
ManagementContextAutoConfiguration.class,
ServletManagementContextAutoConfiguration.class })
......
......@@ -19,10 +19,10 @@ package org.springframework.boot.actuate.autoconfigure.integrationtest;
import org.junit.Test;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.actuate.health.HealthReactiveWebEndpointExtension;
import org.springframework.boot.actuate.health.HealthWebEndpointExtension;
import org.springframework.boot.actuate.health.StatusReactiveWebEndpointExtension;
import org.springframework.boot.actuate.health.StatusWebEndpointExtension;
import org.springframework.boot.actuate.health.HealthEndpointWebExtension;
import org.springframework.boot.actuate.health.ReactiveHealthEndpointWebExtension;
import org.springframework.boot.actuate.health.ReactiveStatusEndpointWebExtension;
import org.springframework.boot.actuate.health.StatusEndpointWebExtension;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
import org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration;
......@@ -59,25 +59,25 @@ public class WebEndpointsAutoConfigurationIntegrationTests {
servletWebRunner()
.run((context) -> context.getBean(WebEndpointTestApplication.class));
servletWebRunner().run((context) -> assertThat(context)
.hasSingleBean(HealthWebEndpointExtension.class));
.hasSingleBean(HealthEndpointWebExtension.class));
}
@Test
public void statusEndpointWebExtensionIsAutoConfigured() {
servletWebRunner().run((context) -> assertThat(context)
.hasSingleBean(StatusWebEndpointExtension.class));
.hasSingleBean(StatusEndpointWebExtension.class));
}
@Test
public void healthEndpointReactiveWebExtensionIsAutoConfigured() {
reactiveWebRunner().run((context) -> assertThat(context)
.hasSingleBean(HealthReactiveWebEndpointExtension.class));
.hasSingleBean(ReactiveHealthEndpointWebExtension.class));
}
@Test
public void statusEndpointReactiveWebExtensionIsAutoConfigured() {
reactiveWebRunner().run((context) -> assertThat(context)
.hasSingleBean(StatusReactiveWebEndpointExtension.class));
.hasSingleBean(ReactiveStatusEndpointWebExtension.class));
}
private WebApplicationContextRunner servletWebRunner() {
......
......@@ -21,6 +21,7 @@ import org.junit.Test;
import org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.servlet.WebMvcEndpointManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
......@@ -65,10 +66,11 @@ public class WebMvcEndpointCorsIntegrationTests {
this.context.register(JacksonAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
WebMvcAutoConfiguration.class, DispatcherServletAutoConfiguration.class,
EndpointAutoConfiguration.class, ManagementContextAutoConfiguration.class,
EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,
ManagementContextAutoConfiguration.class,
ServletManagementContextAutoConfiguration.class,
BeansEndpointAutoConfiguration.class);
TestPropertyValues.of("endpoints.default.web.enabled:true").applyTo(this.context);
TestPropertyValues.of("management.endpoints.web.expose:*").applyTo(this.context);
}
@Test
......@@ -83,7 +85,8 @@ public class WebMvcEndpointCorsIntegrationTests {
@Test
public void settingAllowedOriginsEnablesCors() throws Exception {
TestPropertyValues.of("management.endpoints.cors.allowed-origins:foo.example.com")
TestPropertyValues
.of("management.endpoints.web.cors.allowed-origins:foo.example.com")
.applyTo(this.context);
createMockMvc()
.perform(options("/application/beans").header("Origin", "bar.example.com")
......@@ -94,7 +97,8 @@ public class WebMvcEndpointCorsIntegrationTests {
@Test
public void maxAgeDefaultsTo30Minutes() throws Exception {
TestPropertyValues.of("management.endpoints.cors.allowed-origins:foo.example.com")
TestPropertyValues
.of("management.endpoints.web.cors.allowed-origins:foo.example.com")
.applyTo(this.context);
performAcceptedCorsRequest()
.andExpect(header().string(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "1800"));
......@@ -102,15 +106,18 @@ public class WebMvcEndpointCorsIntegrationTests {
@Test
public void maxAgeCanBeConfigured() throws Exception {
TestPropertyValues.of("management.endpoints.cors.allowed-origins:foo.example.com",
"management.endpoints.cors.max-age: 2400").applyTo(this.context);
TestPropertyValues
.of("management.endpoints.web.cors.allowed-origins:foo.example.com",
"management.endpoints.web.cors.max-age: 2400")
.applyTo(this.context);
performAcceptedCorsRequest()
.andExpect(header().string(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "2400"));
}
@Test
public void requestsWithDisallowedHeadersAreRejected() throws Exception {
TestPropertyValues.of("management.endpoints.cors.allowed-origins:foo.example.com")
TestPropertyValues
.of("management.endpoints.web.cors.allowed-origins:foo.example.com")
.applyTo(this.context);
createMockMvc()
.perform(options("/application/beans").header("Origin", "foo.example.com")
......@@ -122,8 +129,8 @@ public class WebMvcEndpointCorsIntegrationTests {
@Test
public void allowedHeadersCanBeConfigured() throws Exception {
TestPropertyValues
.of("management.endpoints.cors.allowed-origins:foo.example.com",
"management.endpoints.cors.allowed-headers:Alpha,Bravo")
.of("management.endpoints.web.cors.allowed-origins:foo.example.com",
"management.endpoints.web.cors.allowed-headers:Alpha,Bravo")
.applyTo(this.context);
createMockMvc()
.perform(options("/application/beans").header("Origin", "foo.example.com")
......@@ -135,7 +142,8 @@ public class WebMvcEndpointCorsIntegrationTests {
@Test
public void requestsWithDisallowedMethodsAreRejected() throws Exception {
TestPropertyValues.of("management.endpoints.cors.allowed-origins:foo.example.com")
TestPropertyValues
.of("management.endpoints.web.cors.allowed-origins:foo.example.com")
.applyTo(this.context);
createMockMvc()
.perform(options("/application/health")
......@@ -147,8 +155,8 @@ public class WebMvcEndpointCorsIntegrationTests {
@Test
public void allowedMethodsCanBeConfigured() throws Exception {
TestPropertyValues
.of("management.endpoints.cors.allowed-origins:foo.example.com",
"management.endpoints.cors.allowed-methods:GET,HEAD")
.of("management.endpoints.web.cors.allowed-origins:foo.example.com",
"management.endpoints.web.cors.allowed-methods:GET,HEAD")
.applyTo(this.context);
createMockMvc()
.perform(options("/application/beans")
......@@ -161,8 +169,8 @@ public class WebMvcEndpointCorsIntegrationTests {
@Test
public void credentialsCanBeAllowed() throws Exception {
TestPropertyValues
.of("management.endpoints.cors.allowed-origins:foo.example.com",
"management.endpoints.cors.allow-credentials:true")
.of("management.endpoints.web.cors.allowed-origins:foo.example.com",
"management.endpoints.web.cors.allow-credentials:true")
.applyTo(this.context);
performAcceptedCorsRequest().andExpect(
header().string(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"));
......@@ -171,8 +179,8 @@ public class WebMvcEndpointCorsIntegrationTests {
@Test
public void credentialsCanBeDisabled() throws Exception {
TestPropertyValues
.of("management.endpoints.cors.allowed-origins:foo.example.com",
"management.endpoints.cors.allow-credentials:false")
.of("management.endpoints.web.cors.allowed-origins:foo.example.com",
"management.endpoints.web.cors.allow-credentials:false")
.applyTo(this.context);
performAcceptedCorsRequest().andExpect(
header().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS));
......
......@@ -19,6 +19,7 @@ package org.springframework.boot.actuate.autoconfigure.integrationtest;
import org.junit.Test;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
......@@ -52,7 +53,7 @@ public class WebMvcEndpointExposureIntegrationTests {
JacksonAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
WebMvcAutoConfiguration.class, EndpointAutoConfiguration.class,
EndpointAutoConfiguration.class,
WebEndpointAutoConfiguration.class,
ManagementContextAutoConfiguration.class,
ServletManagementContextAutoConfiguration.class,
ManagementContextAutoConfiguration.class,
......@@ -79,9 +80,9 @@ public class WebMvcEndpointExposureIntegrationTests {
}
@Test
public void webEndpointsCanBeEnabled() {
public void webEndpointsCanBeExposed() {
WebApplicationContextRunner contextRunner = this.contextRunner
.withPropertyValues("endpoints.default.web.enabled=true");
.withPropertyValues("management.endpoints.web.expose=*");
contextRunner.run((context) -> {
MockMvc mvc = MockMvcBuilders.webAppContextSetup(context).build();
assertThat(isExposed(mvc, HttpMethod.GET, "beans")).isTrue();
......@@ -99,26 +100,46 @@ public class WebMvcEndpointExposureIntegrationTests {
}
@Test
public void singleWebEndpointCanBeEnabled() {
WebApplicationContextRunner contextRunner = this.contextRunner.withPropertyValues(
"endpoints.default.web.enabled=false",
"endpoints.beans.web.enabled=true");
public void singleWebEndpointCanBeExposed() {
WebApplicationContextRunner contextRunner = this.contextRunner
.withPropertyValues("management.endpoints.web.expose=beans");
contextRunner.run((context) -> {
MockMvc mvc = MockMvcBuilders.webAppContextSetup(context).build();
assertThat(isExposed(mvc, HttpMethod.GET, "autoconfig")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "beans")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "conditions")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "configprops")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "env")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "health")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "info")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "info")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "mappings")).isFalse();
assertThat(isExposed(mvc, HttpMethod.POST, "shutdown")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "status")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "status")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "threaddump")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "trace")).isFalse();
});
}
@Test
public void singleWebEndpointCanBeExcluded() {
WebApplicationContextRunner contextRunner = this.contextRunner.withPropertyValues(
"management.endpoints.web.expose=*",
"management.endpoints.web.exclude=shutdown");
contextRunner.run((context) -> {
MockMvc mvc = MockMvcBuilders.webAppContextSetup(context).build();
assertThat(isExposed(mvc, HttpMethod.GET, "beans")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "conditions")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "configprops")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "env")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "health")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "info")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "mappings")).isTrue();
assertThat(isExposed(mvc, HttpMethod.POST, "shutdown")).isFalse();
assertThat(isExposed(mvc, HttpMethod.GET, "status")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "threaddump")).isTrue();
assertThat(isExposed(mvc, HttpMethod.GET, "trace")).isTrue();
});
}
private boolean isExposed(MockMvc mockMvc, HttpMethod method, String path)
throws Exception {
path = "/application/" + path;
......
......@@ -22,6 +22,7 @@ import org.junit.Test;
import org.springframework.boot.actuate.autoconfigure.audit.AuditAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
......@@ -91,7 +92,7 @@ public class WebMvcEndpointIntegrationTests {
this.context = new AnnotationConfigWebApplicationContext();
this.context.register(SecureConfiguration.class);
TestPropertyValues.of("management.endpoints.web.base-path:/management",
"endpoints.default.web.enabled=true").applyTo(this.context);
"management.endpoints.web.expose=*").applyTo(this.context);
MockMvc mockMvc = createSecureMockMvc();
mockMvc.perform(get("/management/beans")).andExpect(status().isOk());
}
......@@ -112,6 +113,7 @@ public class WebMvcEndpointIntegrationTests {
@ImportAutoConfiguration({ JacksonAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, EndpointAutoConfiguration.class,
WebEndpointAutoConfiguration.class,
ServletManagementContextAutoConfiguration.class, AuditAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, WebMvcAutoConfiguration.class,
ManagementContextAutoConfiguration.class, AuditAutoConfiguration.class,
......
......@@ -49,7 +49,8 @@ public class LiquibaseEndpointAutoConfigurationTests {
@Test
public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean()
throws Exception {
this.contextRunner.withPropertyValues("endpoints.liquibase.enabled:false")
this.contextRunner
.withPropertyValues("management.endpoint.liquibase.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(LiquibaseEndpoint.class));
}
......
......@@ -63,7 +63,8 @@ public class LogFileWebEndpointManagementContextConfigurationTests {
@Test
public void logFileWebEndpointIsAutoConfiguredWhenExternalFileIsSet() {
this.contextRunner
.withPropertyValues("endpoints.logfile.external-file:external.log")
.withPropertyValues(
"management.endpoint.logfile.external-file:external.log")
.run((context) -> assertThat(context)
.hasSingleBean(LogFileWebEndpoint.class));
}
......@@ -72,7 +73,7 @@ public class LogFileWebEndpointManagementContextConfigurationTests {
public void logFileWebEndpointCanBeDisabled() {
this.contextRunner
.withPropertyValues("logging.file:test.log",
"endpoints.logfile.enabled:false")
"management.endpoint.logfile.enabled:false")
.run((context) -> assertThat(context)
.hasSingleBean(LogFileWebEndpoint.class));
}
......@@ -81,9 +82,8 @@ public class LogFileWebEndpointManagementContextConfigurationTests {
public void logFileWebEndpointUsesConfiguredExternalFile() throws IOException {
File file = this.temp.newFile("logfile");
FileCopyUtils.copy("--TEST--".getBytes(), file);
this.contextRunner
.withPropertyValues(
"endpoints.logfile.external-file:" + file.getAbsolutePath())
this.contextRunner.withPropertyValues(
"management.endpoint.logfile.external-file:" + file.getAbsolutePath())
.run((context) -> {
assertThat(context).hasSingleBean(LogFileWebEndpoint.class);
LogFileWebEndpoint endpoint = context
......
......@@ -49,8 +49,9 @@ public class LoggersEndpointAutoConfigurationTests {
@Test
public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean()
throws Exception {
this.contextRunner.withPropertyValues("endpoints.loggers.enabled:false").run(
(context) -> assertThat(context).doesNotHaveBean(LoggersEndpoint.class));
this.contextRunner.withPropertyValues("management.endpoint.loggers.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(LoggersEndpoint.class));
}
@Configuration
......
......@@ -31,7 +31,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class HeapDumpWebEndpointManagementContextConfigurationTests {
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withPropertyValues("endpoints.default.web.enabled:true")
.withPropertyValues("management.endpoints.web.expose:*")
.withUserConfiguration(
HeapDumpWebEndpointManagementContextConfiguration.class);
......@@ -43,7 +43,8 @@ public class HeapDumpWebEndpointManagementContextConfigurationTests {
@Test
public void runWhenDisabledShouldNotCreateIndicator() throws Exception {
this.contextRunner.withPropertyValues("endpoints.heapdump.enabled:false")
this.contextRunner
.withPropertyValues("management.endpoint.heapdump.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(HeapDumpWebEndpoint.class));
}
......
......@@ -44,7 +44,8 @@ public class ThreadDumpEndpointAutoConfigurationTests {
@Test
public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean()
throws Exception {
this.contextRunner.withPropertyValues("endpoints.threaddump.enabled:false")
this.contextRunner
.withPropertyValues("management.endpoint.threaddump.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(ThreadDumpEndpoint.class));
}
......
......@@ -46,7 +46,8 @@ public class ScheduledTasksEndpointAutoConfigurationTests {
@Test
public void endpointCanBeDisabled() {
this.contextRunner.withPropertyValues("endpoints.scheduledtasks.enabled:false")
this.contextRunner
.withPropertyValues("management.endpoint.scheduledtasks.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(ScheduledTasksEndpoint.class));
}
......
......@@ -49,8 +49,10 @@ public class SessionsEndpointAutoConfigurationTests {
@Test
public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean()
throws Exception {
this.contextRunner.withPropertyValues("endpoints.sessions.enabled:false").run(
(context) -> assertThat(context).doesNotHaveBean(SessionsEndpoint.class));
this.contextRunner
.withPropertyValues("management.endpoint.sessions.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(SessionsEndpoint.class));
}
@Configuration
......
......@@ -44,8 +44,9 @@ public class TraceEndpointAutoConfigurationTests {
@Test
public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean()
throws Exception {
this.contextRunner.withPropertyValues("endpoints.trace.enabled:false").run(
(context) -> assertThat(context).doesNotHaveBean(TraceEndpoint.class));
this.contextRunner.withPropertyValues("management.endpoint.trace.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(TraceEndpoint.class));
}
}
......@@ -22,13 +22,12 @@ import java.util.Map;
import org.junit.Test;
import org.springframework.boot.actuate.endpoint.DefaultEnablement;
import org.springframework.boot.actuate.endpoint.EndpointInfo;
import org.springframework.boot.actuate.endpoint.OperationType;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.OperationRequestPredicate;
import org.springframework.boot.actuate.endpoint.web.WebEndpointHttpMethod;
import org.springframework.boot.actuate.endpoint.web.WebEndpointOperation;
import org.springframework.boot.actuate.endpoint.web.WebOperation;
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
import org.springframework.boot.endpoint.web.EndpointMapping;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
......@@ -136,12 +135,12 @@ public class RequestMappingEndpointTests {
OperationRequestPredicate requestPredicate = new OperationRequestPredicate("test",
WebEndpointHttpMethod.GET, Collections.singletonList("application/json"),
Collections.singletonList("application/json"));
WebEndpointOperation operation = new WebEndpointOperation(OperationType.READ,
WebOperation operation = new WebOperation(OperationType.READ,
(arguments) -> "Invoked", true, requestPredicate, "test");
WebMvcEndpointHandlerMapping mapping = new WebMvcEndpointHandlerMapping(
new EndpointMapping("application"),
Collections.singleton(new EndpointInfo<>("test",
DefaultEnablement.ENABLED, Collections.singleton(operation))),
Collections.singleton(new EndpointInfo<>("test", true,
Collections.singleton(operation))),
new EndpointMediaTypes(Arrays.asList("application/vnd.test+json"),
Arrays.asList("application/vnd.test+json")));
mapping.setApplicationContext(new StaticApplicationContext());
......
......@@ -21,21 +21,21 @@ import java.util.Date;
import org.springframework.boot.actuate.audit.AuditEventsEndpoint.AuditEventsDescriptor;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointExtension;
import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;
import org.springframework.lang.Nullable;
/**
* {@link WebEndpointExtension} for the {@link AuditEventsEndpoint}.
* {@link EndpointWebExtension} for the {@link AuditEventsEndpoint}.
*
* @author Vedran Pavic
* @since 2.0.0
*/
@WebEndpointExtension(endpoint = AuditEventsEndpoint.class)
public class AuditEventsWebEndpointExtension {
@EndpointWebExtension(endpoint = AuditEventsEndpoint.class)
public class AuditEventsEndpointWebExtension {
private final AuditEventsEndpoint delegate;
public AuditEventsWebEndpointExtension(AuditEventsEndpoint delegate) {
public AuditEventsEndpointWebExtension(AuditEventsEndpoint delegate) {
this.delegate = delegate;
}
......
......@@ -20,7 +20,7 @@ import java.util.Date;
import org.springframework.boot.actuate.audit.AuditEventsEndpoint.AuditEventsDescriptor;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.jmx.annotation.JmxEndpointExtension;
import org.springframework.boot.actuate.endpoint.jmx.annotation.EndpointJmxExtension;
/**
* JMX-specific extension of the {@link AuditEventsEndpoint}.
......@@ -29,7 +29,7 @@ import org.springframework.boot.actuate.endpoint.jmx.annotation.JmxEndpointExten
* @author Andy Wilkinson
* @since 2.0.0
*/
@JmxEndpointExtension(endpoint = AuditEventsEndpoint.class)
@EndpointJmxExtension(endpoint = AuditEventsEndpoint.class)
public class AuditEventsJmxEndpointExtension {
private final AuditEventsEndpoint delegate;
......
......@@ -20,7 +20,6 @@ import java.util.Collections;
import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.boot.actuate.endpoint.DefaultEnablement;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.context.ApplicationContext;
......@@ -35,7 +34,7 @@ import org.springframework.context.ConfigurableApplicationContext;
* @author Andy Wilkinson
* @since 2.0.0
*/
@Endpoint(id = "shutdown", defaultEnablement = DefaultEnablement.DISABLED)
@Endpoint(id = "shutdown", enableByDefault = false)
public class ShutdownEndpoint implements ApplicationContextAware {
private static final Map<String, String> NO_CONTEXT_MESSAGE = Collections
......
......@@ -17,26 +17,21 @@
package org.springframework.boot.actuate.endpoint;
/**
* Enumerate the enablement options for an endpoint.
* Strategy class that can be used to filter discovered endpoints.
*
* @author Stephane Nicoll
* @author Phillip Webb
* @param <T> the type of the endpoint's operations
* @since 2.0.0
*/
public enum DefaultEnablement {
@FunctionalInterface
public interface EndpointFilter<T extends Operation> {
/**
* The endpoint is enabled unless explicitly disabled.
* Return {@code true} if the filter matches.
* @param info the endpoint info
* @param discoverer the endpoint discoverer
* @return {@code true} if the filter matches
*/
ENABLED,
/**
* The endpoint is disabled unless explicitly enabled.
*/
DISABLED,
/**
* The endpoint's enablement defaults to the "default" settings.
*/
NEUTRAL
boolean match(EndpointInfo<T> info, EndpointDiscoverer<T> discoverer);
}
......@@ -17,6 +17,9 @@
package org.springframework.boot.actuate.endpoint;
import java.util.Collection;
import java.util.Collections;
import org.springframework.util.Assert;
/**
* Information describing an endpoint.
......@@ -29,7 +32,7 @@ public class EndpointInfo<T extends Operation> {
private final String id;
private final DefaultEnablement defaultEnablement;
private final boolean enableByDefault;
private final Collection<T> operations;
......@@ -37,14 +40,15 @@ public class EndpointInfo<T extends Operation> {
* Creates a new {@code EndpointInfo} describing an endpoint with the given {@code id}
* and {@code operations}.
* @param id the id of the endpoint
* @param defaultEnablement the {@link DefaultEnablement} of the endpoint
* @param enableByDefault if the endpoint is enabled by default
* @param operations the operations of the endpoint
*/
public EndpointInfo(String id, DefaultEnablement defaultEnablement,
Collection<T> operations) {
public EndpointInfo(String id, boolean enableByDefault, Collection<T> operations) {
Assert.hasText(id, "ID must not be empty");
Assert.notNull(operations, "Operations must not be null");
this.id = id;
this.defaultEnablement = defaultEnablement;
this.operations = operations;
this.enableByDefault = enableByDefault;
this.operations = Collections.unmodifiableCollection(operations);
}
/**
......@@ -56,11 +60,11 @@ public class EndpointInfo<T extends Operation> {
}
/**
* Return the {@link DefaultEnablement} of the endpoint.
* @return the default enablement
* Returns if the endpoint is enabled by default.
* @return if the endpoint is enabled by default
*/
public DefaultEnablement getDefaultEnablement() {
return this.defaultEnablement;
public boolean isEnableByDefault() {
return this.enableByDefault;
}
/**
......
......@@ -33,14 +33,14 @@ public class Operation {
/**
* Creates a new {@code EndpointOperation} for an operation of the given {@code type}.
* The operation can be performed using the given {@code operationInvoker}.
* @param type the type of the operation
* @param operationInvoker used to perform the operation
* @param operationType the type of the operation
* @param invoker used to perform the operation
* @param blocking whether or not this is a blocking operation
*/
public Operation(OperationType type, OperationInvoker operationInvoker,
public Operation(OperationType operationType, OperationInvoker invoker,
boolean blocking) {
this.type = type;
this.invoker = operationInvoker;
this.type = operationType;
this.invoker = invoker;
this.blocking = blocking;
}
......
......@@ -36,7 +36,6 @@ public @interface DeleteOperation {
/**
* The media type of the result of the operation.
*
* @return the media type
*/
String[] produces() default {};
......
......@@ -22,14 +22,28 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.actuate.endpoint.DefaultEnablement;
import org.springframework.boot.actuate.endpoint.EndpointExposure;
/**
* Identifies a type as being an endpoint.
* Identifies a type as being an actuator endpoint that provides information about the
* running application. Endpoints can be exposed over a variety of technologies including
* JMX and HTTP.
* <p>
* Most {@code @Endpoint} classes will declare one or more
* {@link ReadOperation @ReadOperation}, {@link WriteOperation @WriteOperation},
* {@link DeleteOperation @DeleteOperation} annotated methods which will be automatically
* adapted to the exposing technology (JMX, Spring MVC, Spring WebFlux, Jersey etc.).
* <p>
* {@code @Endpoint} represents the lowest common denominator for endpoints and
* intentionally limits the sorts of operation methods that may be defined in order to
* support the broadest possible range of exposure technologies. If you need deeper
* support for a specific technology you can either write an endpoint that is
* {@link FilteredEndpoint filtered} to a certain technology, or provide
* {@link EndpointExtension extension} for the broader endpoint.
*
* @author Andy Wilkinson
* @author Phillip Webb
* @since 2.0.0
* @see EndpointExtension
* @see FilteredEndpoint
* @see AnnotationEndpointDiscoverer
*/
@Target(ElementType.TYPE)
......@@ -41,20 +55,12 @@ public @interface Endpoint {
* The id of the endpoint.
* @return the id
*/
String id();
/**
* Defines the {@link EndpointExposure technologies} over which the endpoint should be
* exposed. By default, all technologies are supported.
* @return the supported endpoint exposure technologies
*/
EndpointExposure[] exposure() default {};
String id() default "";
/**
* Defines the {@link DefaultEnablement} of the endpoint. By default, the endpoint's
* enablement defaults to the "default" settings.
* @return the default enablement
* If the endpoint should be enabled or disabled by default.
* @return {@code true} if the endpoint is enabled by default
*/
DefaultEnablement defaultEnablement() default DefaultEnablement.NEUTRAL;
boolean enableByDefault() default true;
}
......@@ -14,54 +14,54 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.endpoint;
package org.springframework.boot.actuate.endpoint.annotation;
import java.util.Collection;
import java.util.stream.Collectors;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.actuate.endpoint.EndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.EndpointExposure;
import org.springframework.boot.actuate.endpoint.EndpointInfo;
import org.springframework.boot.actuate.endpoint.EndpointFilter;
import org.springframework.boot.actuate.endpoint.Operation;
import org.springframework.core.env.Environment;
import org.springframework.core.annotation.AliasFor;
/**
* Provides the endpoints that are enabled according to an {@link EndpointDiscoverer} and
* the current {@link Environment}.
* Meta-annotation used to indicate that an annotation provides extension support for an
* endpoint. Extensions allow additional technology specific {@link Operation operations}
* to be added to an existing endpoint. For example, a web extension may offer variations
* of a read operation operation to support filtering based on a query parameter.
* <p>
* Extension annotations must provide an {@link EndpointFilter} to restrict when the
* extension applies. The {@code endpoint} attribute is usually re-declared using
* {@link AliasFor @AliasFor}. For example: <pre class="code">
* &#64;EndpointExtension(filter = WebEndpointFilter.class)
* public &#64;interface EndpointWebExtension {
*
* @param <T> the endpoint operation type
* @author Stephane Nicoll
* &#64;AliasFor(annotation = EndpointExtension.class, attribute = "endpoint")
* Class<?> endpoint();
*
* }
* </pre>
*
* @author Phillip Webb
* @since 2.0.0
*/
public class EndpointProvider<T extends Operation> {
private final EndpointDiscoverer<T> discoverer;
private final EndpointEnablementProvider endpointEnablementProvider;
private final EndpointExposure exposure;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EndpointExtension {
/**
* Creates a new instance.
* @param environment the environment to use to check the endpoints that are enabled
* @param discoverer the discoverer to get the initial set of endpoints
* @param exposure the exposure technology for the endpoint
* The filter class used to determine when the extension applies.
* @return the filter class
*/
public EndpointProvider(Environment environment, EndpointDiscoverer<T> discoverer,
EndpointExposure exposure) {
this.discoverer = discoverer;
this.endpointEnablementProvider = new EndpointEnablementProvider(environment);
this.exposure = exposure;
}
public Collection<EndpointInfo<T>> getEndpoints() {
return this.discoverer.discoverEndpoints().stream().filter(this::isEnabled)
.collect(Collectors.toList());
}
Class<? extends EndpointFilter<?>> filter();
private boolean isEnabled(EndpointInfo<?> endpoint) {
return this.endpointEnablementProvider.getEndpointEnablement(endpoint.getId(),
endpoint.getDefaultEnablement(), this.exposure).isEnabled();
}
/**
* The class of the endpoint to extend.
* @return the class endpoint to extend
*/
Class<?> endpoint() default Void.class;
}
/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.endpoint.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.actuate.endpoint.EndpointFilter;
/**
* Annotation that can be used on an {@link Endpoint @Endpoint} to implement implicit
* filtering. Often used as a meta-annotation on technology specific endpoint annotations,
* for example:<pre class="code">
* &#64;Endpoint
* &#64;FilteredEndpoint(WebEndpointFilter.class)
* public &#64;interface WebEndpoint {
*
* &#64;AliasFor(annotation = Endpoint.class, attribute = "id")
* String id();
*
* &#64;AliasFor(annotation = Endpoint.class, attribute = "enableByDefault")
* boolean enableByDefault() default true;
*
* } </pre>
* @author Phillip Webb
* @since 2.0.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FilteredEndpoint {
/**
* The filter class to use.
* @return the filter class
*/
Class<? extends EndpointFilter<?>> value();
}
/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.endpoint.annotation;
import org.springframework.boot.actuate.endpoint.Operation;
import org.springframework.boot.actuate.endpoint.OperationInvoker;
import org.springframework.boot.actuate.endpoint.reflect.OperationMethodInfo;
/**
* Factory to creates an {@link Operation} for an annotated method on an
* {@link Endpoint @Endpoint}.
*
* @param <T> the {@link Operation} type
* @author Andy Wilkinson
* @author Stephane Nicoll
* @author Phillip Webb
*/
@FunctionalInterface
public interface OperationFactory<T extends Operation> {
/**
* Creates an {@link Operation} for an operation on an endpoint.
* @param endpointId the id of the endpoint
* @param target the target that implements the operation
* @param methodInfo the method on the bean that implements the operation
* @param invoker the invoker that should be used for the operation
* @return the operation info that describes the operation
*/
T createOperation(String endpointId, OperationMethodInfo methodInfo, Object target,
OperationInvoker invoker);
}
......@@ -35,7 +35,6 @@ public @interface ReadOperation {
/**
* The media type of the result of the operation.
*
* @return the media type
*/
String[] produces() default {};
......
......@@ -35,7 +35,6 @@ public @interface WriteOperation {
/**
* The media type of the result of the operation.
*
* @return the media type
*/
String[] produces() default {};
......
......@@ -14,35 +14,41 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.endpoint;
package org.springframework.boot.actuate.endpoint.cache;
import org.springframework.boot.actuate.endpoint.cache.CachingConfiguration;
import org.springframework.boot.actuate.endpoint.cache.CachingConfigurationFactory;
import org.springframework.core.env.Environment;
import java.util.function.Function;
import org.springframework.boot.actuate.endpoint.OperationInvoker;
import org.springframework.boot.actuate.endpoint.OperationType;
import org.springframework.boot.actuate.endpoint.reflect.OperationMethodInfo;
import org.springframework.boot.actuate.endpoint.reflect.OperationMethodInvokerAdvisor;
/**
* Default {@link CachingConfigurationFactory} implementation that use the
* {@link Environment} to extract the caching settings of each endpoint.
* {@link OperationMethodInvokerAdvisor} to optionally wrap an {@link OperationInvoker}
* with a {@link CachingOperationInvoker}.
*
* @author Stephane Nicoll
* @since 2.0.0
*/
public class DefaultCachingConfigurationFactory implements CachingConfigurationFactory {
public class CachingOperationInvokerAdvisor implements OperationMethodInvokerAdvisor {
private final Environment environment;
private final Function<String, Long> endpointIdTimeToLive;
/**
* Create a new instance with the {@link Environment} to use.
* @param environment the environment
*/
DefaultCachingConfigurationFactory(Environment environment) {
this.environment = environment;
public CachingOperationInvokerAdvisor(Function<String, Long> endpointIdTimeToLive) {
this.endpointIdTimeToLive = endpointIdTimeToLive;
}
@Override
public CachingConfiguration getCachingConfiguration(String endpointId) {
String key = String.format("endpoints.%s.cache.time-to-live", endpointId);
Long timeToLive = this.environment.getProperty(key, Long.class, 0L);
return new CachingConfiguration(timeToLive);
public OperationInvoker apply(String endpointId, OperationMethodInfo methodInfo,
OperationInvoker invoker) {
if (methodInfo.getOperationType() == OperationType.READ
&& methodInfo.getParameters().isEmpty()) {
Long timeToLive = this.endpointIdTimeToLive.apply(endpointId);
if (timeToLive != null && timeToLive > 0) {
return new CachingOperationInvoker(invoker, timeToLive);
}
}
return invoker;
}
}
......@@ -16,8 +16,8 @@
package org.springframework.boot.actuate.endpoint.convert;
import org.springframework.boot.actuate.endpoint.ParameterMapper;
import org.springframework.boot.actuate.endpoint.ParameterMappingException;
import org.springframework.boot.actuate.endpoint.reflect.ParameterMapper;
import org.springframework.boot.actuate.endpoint.reflect.ParameterMappingException;
import org.springframework.boot.context.properties.bind.convert.BinderConversionService;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.support.DefaultFormattingConversionService;
......
......@@ -33,8 +33,8 @@ import javax.management.ReflectionException;
import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.endpoint.EndpointInfo;
import org.springframework.boot.actuate.endpoint.ParameterMappingException;
import org.springframework.boot.actuate.endpoint.ParametersMissingException;
import org.springframework.boot.actuate.endpoint.reflect.ParameterMappingException;
import org.springframework.boot.actuate.endpoint.reflect.ParametersMissingException;
import org.springframework.util.ClassUtils;
/**
......@@ -76,7 +76,7 @@ public class EndpointMBean implements DynamicMBean {
@Override
public Object invoke(String actionName, Object[] params, String[] signature)
throws MBeanException, ReflectionException {
JmxEndpointOperation operation = this.endpointInfo.getOperations()
JmxOperation operation = this.endpointInfo.getOperations()
.get(actionName);
if (operation != null) {
Map<String, Object> arguments = getArguments(params,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment