diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/ConditionalOnEnabledEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/ConditionalOnEnabledEndpoint.java index dd5dd2833f9..5f5888ab3d0 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/ConditionalOnEnabledEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/ConditionalOnEnabledEndpoint.java @@ -23,7 +23,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.boot.endpoint.Endpoint; -import org.springframework.boot.endpoint.EndpointType; +import org.springframework.boot.endpoint.EndpointDelivery; import org.springframework.context.annotation.Conditional; /** @@ -33,8 +33,8 @@ import org.springframework.context.annotation.Conditional; *

* If no specific {@code endpoints..*} or {@code endpoints.default.*} properties are * defined, the condition matches the {@code enabledByDefault} value regardless of the - * specific {@link EndpointType}, if any. If any property are set, they are evaluated with - * a sensible order of precedence. + * specific {@link EndpointDelivery}, if any. If any property are set, they are evaluated + * with a sensible order of precedence. *

* For instance if {@code endpoints.default.enabled} is {@code false} but * {@code endpoints..enabled} is {@code true}, the condition will match. diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/OnEnabledEndpointCondition.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/OnEnabledEndpointCondition.java index f99ad69b02a..b0fc06a28ab 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/OnEnabledEndpointCondition.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/OnEnabledEndpointCondition.java @@ -22,7 +22,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionMessage; import org.springframework.boot.autoconfigure.condition.ConditionOutcome; import org.springframework.boot.autoconfigure.condition.SpringBootCondition; import org.springframework.boot.endpoint.Endpoint; -import org.springframework.boot.endpoint.EndpointType; +import org.springframework.boot.endpoint.EndpointDelivery; import org.springframework.boot.endpoint.jmx.JmxEndpointExtension; import org.springframework.boot.endpoint.web.WebEndpointExtension; import org.springframework.context.annotation.Bean; @@ -30,6 +30,7 @@ import org.springframework.context.annotation.ConditionContext; import org.springframework.core.annotation.AnnotationUtils; 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; @@ -44,14 +45,9 @@ class OnEnabledEndpointCondition extends SpringBootCondition { @Override public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { - EndpointAttributes endpoint = getEndpointAttributes(context, metadata); - if (!StringUtils.hasText(endpoint.id)) { - throw new IllegalStateException("Endpoint id could not be determined"); - } - EndpointEnablementProvider enablementProvider = new EndpointEnablementProvider( - context.getEnvironment()); - EndpointEnablement endpointEnablement = enablementProvider.getEndpointEnablement( - endpoint.id, endpoint.enabled, endpoint.endpointType); + 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())); @@ -59,24 +55,27 @@ class OnEnabledEndpointCondition extends SpringBootCondition { private EndpointAttributes getEndpointAttributes(ConditionContext context, AnnotatedTypeMetadata metadata) { - if (metadata instanceof MethodMetadata - && metadata.isAnnotated(Bean.class.getName())) { - MethodMetadata methodMetadata = (MethodMetadata) metadata; - try { - // We should be safe to load at this point since we are in the - // REGISTER_BEAN phase - Class returnType = ClassUtils.forName( - methodMetadata.getReturnTypeName(), context.getClassLoader()); - return extractEndpointAttributes(returnType); - } - catch (Throwable ex) { - throw new IllegalStateException("Failed to extract endpoint id for " - + methodMetadata.getDeclaringClassName() + "." - + methodMetadata.getMethodName(), ex); - } - } - throw new IllegalStateException( + Assert.state( + metadata instanceof MethodMetadata + && metadata.isAnnotated(Bean.class.getName()), "OnEnabledEndpointCondition may only be used on @Bean methods"); + return getEndpointAttributes(context, (MethodMetadata) metadata); + } + + private EndpointAttributes getEndpointAttributes(ConditionContext context, + MethodMetadata methodMetadata) { + try { + // We should be safe to load at this point since we are in the + // REGISTER_BEAN phase + Class returnType = ClassUtils.forName(methodMetadata.getReturnTypeName(), + context.getClassLoader()); + return extractEndpointAttributes(returnType); + } + catch (Throwable ex) { + throw new IllegalStateException("Failed to extract endpoint id for " + + methodMetadata.getDeclaringClassName() + "." + + methodMetadata.getMethodName(), ex); + } } protected EndpointAttributes extractEndpointAttributes(Class type) { @@ -105,11 +104,10 @@ class OnEnabledEndpointCondition extends SpringBootCondition { if (endpoint == null) { return null; } - // If both types are set, all techs are exposed - EndpointType endpointType = (endpoint.types().length == 1 ? endpoint.types()[0] - : null); + // If both types are set, all delivery technologies are exposed + EndpointDelivery[] delivery = endpoint.delivery(); return new EndpointAttributes(endpoint.id(), endpoint.enabledByDefault(), - endpointType); + (delivery.length == 1 ? delivery[0] : null)); } private static class EndpointAttributes { @@ -118,12 +116,19 @@ class OnEnabledEndpointCondition extends SpringBootCondition { private final boolean enabled; - private final EndpointType endpointType; + private final EndpointDelivery delivery; - EndpointAttributes(String id, boolean enabled, EndpointType endpointType) { + EndpointAttributes(String id, boolean enabled, EndpointDelivery delivery) { + if (!StringUtils.hasText(id)) { + throw new IllegalStateException("Endpoint id could not be determined"); + } this.id = id; this.enabled = enabled; - this.endpointType = endpointType; + this.delivery = delivery; + } + + public EndpointEnablement getEnablement(EndpointEnablementProvider provider) { + return provider.getEndpointEnablement(this.id, this.enabled, this.delivery); } } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/EndpointInfrastructureAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/EndpointInfrastructureAutoConfiguration.java index a228d133d3f..16310bdab94 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/EndpointInfrastructureAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/EndpointInfrastructureAutoConfiguration.java @@ -34,7 +34,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.endpoint.ConversionServiceOperationParameterMapper; -import org.springframework.boot.endpoint.EndpointType; +import org.springframework.boot.endpoint.EndpointDelivery; import org.springframework.boot.endpoint.OperationParameterMapper; import org.springframework.boot.endpoint.jmx.EndpointMBeanRegistrar; import org.springframework.boot.endpoint.jmx.JmxAnnotationEndpointDiscoverer; @@ -102,10 +102,10 @@ public class EndpointInfrastructureAutoConfiguration { ObjectProvider objectMapper) { EndpointProvider endpointProvider = new EndpointProvider<>( this.applicationContext.getEnvironment(), endpointDiscoverer, - EndpointType.JMX); + EndpointDelivery.JMX); EndpointMBeanRegistrar endpointMBeanRegistrar = new EndpointMBeanRegistrar( - mBeanServer, new DefaultEndpointObjectNameFactory(properties, - mBeanServer, ObjectUtils.getIdentityHexString(this.applicationContext))); + mBeanServer, new DefaultEndpointObjectNameFactory(properties, mBeanServer, + ObjectUtils.getIdentityHexString(this.applicationContext))); return new JmxEndpointExporter(endpointProvider, endpointMBeanRegistrar, objectMapper.getIfAvailable(ObjectMapper::new)); } @@ -127,7 +127,7 @@ public class EndpointInfrastructureAutoConfiguration { return new EndpointProvider<>(this.applicationContext.getEnvironment(), webEndpointDiscoverer(operationParameterMapper, cachingConfigurationFactory), - EndpointType.WEB); + EndpointDelivery.WEB); } private WebAnnotationEndpointDiscoverer webEndpointDiscoverer( diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/EndpointProvider.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/EndpointProvider.java index ab7eb14f567..bc60c2c6e4b 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/EndpointProvider.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/infrastructure/EndpointProvider.java @@ -20,10 +20,10 @@ import java.util.Collection; import java.util.stream.Collectors; import org.springframework.boot.actuate.autoconfigure.endpoint.support.EndpointEnablementProvider; +import org.springframework.boot.endpoint.EndpointDelivery; import org.springframework.boot.endpoint.EndpointDiscoverer; import org.springframework.boot.endpoint.EndpointInfo; -import org.springframework.boot.endpoint.EndpointOperation; -import org.springframework.boot.endpoint.EndpointType; +import org.springframework.boot.endpoint.Operation; import org.springframework.core.env.Environment; /** @@ -34,25 +34,25 @@ import org.springframework.core.env.Environment; * @author Stephane Nicoll * @since 2.0.0 */ -public final class EndpointProvider { +public final class EndpointProvider { private final EndpointDiscoverer discoverer; private final EndpointEnablementProvider endpointEnablementProvider; - private final EndpointType endpointType; + private final EndpointDelivery delivery; /** * 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 endpointType the type of endpoint to handle + * @param delivery the delivery technology for the endpoint */ public EndpointProvider(Environment environment, EndpointDiscoverer discoverer, - EndpointType endpointType) { + EndpointDelivery delivery) { this.discoverer = discoverer; this.endpointEnablementProvider = new EndpointEnablementProvider(environment); - this.endpointType = endpointType; + this.delivery = delivery; } public Collection> getEndpoints() { @@ -62,7 +62,7 @@ public final class EndpointProvider { private boolean isEnabled(EndpointInfo endpoint) { return this.endpointEnablementProvider.getEndpointEnablement(endpoint.getId(), - endpoint.isEnabledByDefault(), this.endpointType).isEnabled(); + endpoint.isEnabledByDefault(), this.delivery).isEnabled(); } } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/EndpointEnablement.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/EndpointEnablement.java index ea4fe14e7a7..aacfdcf73a9 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/EndpointEnablement.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/EndpointEnablement.java @@ -25,6 +25,7 @@ package org.springframework.boot.actuate.autoconfigure.endpoint.support; public final class EndpointEnablement { private final boolean enabled; + private final String reason; /** diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/EndpointEnablementProvider.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/EndpointEnablementProvider.java index 512fe6f5e09..47aac5f193c 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/EndpointEnablementProvider.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/EndpointEnablementProvider.java @@ -16,9 +16,9 @@ package org.springframework.boot.actuate.autoconfigure.endpoint.support; -import org.springframework.boot.endpoint.EndpointType; +import org.springframework.boot.endpoint.EndpointDelivery; import org.springframework.core.env.Environment; -import org.springframework.util.StringUtils; +import org.springframework.util.Assert; /** * Determines an endpoint's enablement based on the current {@link Environment}. @@ -54,109 +54,111 @@ public class EndpointEnablementProvider { * Return the {@link EndpointEnablement} of an endpoint for a specific tech exposure. * @param endpointId the id of the endpoint * @param enabledByDefault whether the endpoint is enabled by default or not - * @param endpointType the requested {@link EndpointType} + * @param delivery the requested {@link EndpointDelivery} * @return the {@link EndpointEnablement} of that endpoint for the specified - * {@link EndpointType} + * {@link EndpointDelivery} */ public EndpointEnablement getEndpointEnablement(String endpointId, - boolean enabledByDefault, EndpointType endpointType) { - if (!StringUtils.hasText(endpointId)) { - throw new IllegalArgumentException("Endpoint id must have a value"); + boolean enabledByDefault, EndpointDelivery delivery) { + 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, delivery); + if (result != null) { + return result; } - if (endpointId.equals("default")) { - throw new IllegalArgumentException("Endpoint id 'default' is a reserved " - + "value and cannot be used by an endpoint"); + result = findEnablement(getKey(endpointId, "enabled")); + if (result != null) { + return result; } - - if (endpointType != null) { - String endpointTypeKey = createTechSpecificKey(endpointId, endpointType); - EndpointEnablement endpointTypeSpecificOutcome = getEnablementFor( - endpointTypeKey); - if (endpointTypeSpecificOutcome != null) { - return endpointTypeSpecificOutcome; - } - } - else { - // If any tech specific is on at this point we should enable the endpoint - EndpointEnablement anyTechSpecificOutcome = getAnyTechSpecificOutcomeFor( - endpointId); - if (anyTechSpecificOutcome != null) { - return anyTechSpecificOutcome; - } - } - String endpointKey = createKey(endpointId, "enabled"); - EndpointEnablement endpointSpecificOutcome = getEnablementFor(endpointKey); - if (endpointSpecificOutcome != null) { - return endpointSpecificOutcome; - } - // All endpoints specific attributes have been looked at. Checking default value // for the endpoint if (!enabledByDefault) { - return defaultEndpointEnablement(endpointId, false, endpointType); + return getDefaultEndpointEnablement(endpointId, false, delivery); } - - if (endpointType != null) { - String defaultTypeKey = createTechSpecificKey("default", endpointType); - EndpointEnablement globalTypeOutcome = getEnablementFor(defaultTypeKey); - if (globalTypeOutcome != null) { - return globalTypeOutcome; - } - if (!endpointType.isEnabledByDefault()) { - return defaultEndpointEnablement("default", false, endpointType); - } - } - else { - // Check if there is a global tech required - EndpointEnablement anyTechGeneralOutcome = getAnyTechSpecificOutcomeFor( - "default"); - if (anyTechGeneralOutcome != null) { - return anyTechGeneralOutcome; - } - } - - String defaultKey = createKey("default", "enabled"); - EndpointEnablement globalOutCome = getEnablementFor(defaultKey); - if (globalOutCome != null) { - return globalOutCome; - } - return defaultEndpointEnablement(endpointId, enabledByDefault, endpointType); + return getGlobalEndpointEnablement(endpointId, enabledByDefault, + delivery); } - private EndpointEnablement defaultEndpointEnablement(String endpointId, - boolean enabledByDefault, EndpointType endpointType) { - return new EndpointEnablement(enabledByDefault, createDefaultEnablementMessage( - endpointId, enabledByDefault, endpointType)); - } - - private String createDefaultEnablementMessage(String endpointId, - boolean enabledByDefault, EndpointType endpointType) { - StringBuilder sb = new StringBuilder(); - sb.append(String.format("endpoint '%s' ", endpointId)); - if (endpointType != null) { - sb.append(String.format("(%s) ", endpointType.name().toLowerCase())); + private EndpointEnablement findEnablement(String endpointId, + EndpointDelivery delivery) { + if (delivery != null) { + return findEnablement(getKey(endpointId, delivery)); } - sb.append(String.format("is %s by default", - (enabledByDefault ? "enabled" : "disabled"))); - return sb.toString(); + return findEnablementForAnyDeliveryTechnology(endpointId); } - private EndpointEnablement getAnyTechSpecificOutcomeFor(String endpointId) { - for (EndpointType endpointType : EndpointType.values()) { - String key = createTechSpecificKey(endpointId, endpointType); - EndpointEnablement outcome = getEnablementFor(key); - if (outcome != null && outcome.isEnabled()) { - return outcome; + private EndpointEnablement getGlobalEndpointEnablement(String endpointId, + boolean enabledByDefault, EndpointDelivery delivery) { + EndpointEnablement result = findGlobalEndpointEnablement(delivery); + if (result != null) { + return result; + } + result = findEnablement(getKey("default", "enabled")); + if (result != null) { + return result; + } + return getDefaultEndpointEnablement(endpointId, enabledByDefault, + delivery); + } + + private EndpointEnablement findGlobalEndpointEnablement( + EndpointDelivery delivery) { + if (delivery != null) { + EndpointEnablement result = findEnablement(getKey("default", delivery)); + if (result != null) { + return result; + } + if (!delivery.isEnabledByDefault()) { + return getDefaultEndpointEnablement("default", false, delivery); + } + return null; + } + return findEnablementForAnyDeliveryTechnology("default"); + } + + private EndpointEnablement findEnablementForAnyDeliveryTechnology(String endpointId) { + for (EndpointDelivery candidate : EndpointDelivery.values()) { + EndpointEnablement result = findEnablementForDeliveryTechnology(endpointId, + candidate); + if (result != null && result.isEnabled()) { + return result; } } return null; } - private String createTechSpecificKey(String endpointId, EndpointType endpointType) { - return createKey(endpointId, endpointType.name().toLowerCase() + ".enabled"); + private EndpointEnablement findEnablementForDeliveryTechnology(String endpointId, + EndpointDelivery delivery) { + String endpointTypeKey = getKey(endpointId, delivery); + EndpointEnablement endpointTypeSpecificOutcome = findEnablement(endpointTypeKey); + return endpointTypeSpecificOutcome; } - private String createKey(String endpointId, String suffix) { + private EndpointEnablement getDefaultEndpointEnablement(String endpointId, + boolean enabledByDefault, EndpointDelivery delivery) { + return new EndpointEnablement(enabledByDefault, createDefaultEnablementMessage( + endpointId, enabledByDefault, delivery)); + } + + private String createDefaultEnablementMessage(String endpointId, + boolean enabledByDefault, EndpointDelivery delivery) { + StringBuilder message = new StringBuilder(); + message.append(String.format("endpoint '%s' ", endpointId)); + if (delivery != null) { + message.append( + String.format("(%s) ", delivery.name().toLowerCase())); + } + message.append(String.format("is %s by default", + (enabledByDefault ? "enabled" : "disabled"))); + return message.toString(); + } + + private String getKey(String endpointId, EndpointDelivery delivery) { + return getKey(endpointId, delivery.name().toLowerCase() + ".enabled"); + } + + private String getKey(String endpointId, String suffix) { return "endpoints." + endpointId + "." + suffix; } @@ -166,7 +168,7 @@ public class EndpointEnablementProvider { * @param key the key to check * @return the outcome or {@code null} if the key is no set */ - private EndpointEnablement getEnablementFor(String key) { + 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)); diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryWebEndpointServletHandlerMapping.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryWebEndpointServletHandlerMapping.java index 34079b62e7c..5c7b0c79a3f 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryWebEndpointServletHandlerMapping.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryWebEndpointServletHandlerMapping.java @@ -111,7 +111,7 @@ class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebEndpointSe @Override protected void registerMappingForOperation(WebEndpointOperation operation) { registerMapping(createRequestMappingInfo(operation), - new OperationHandler(operation.getOperationInvoker(), operation.getId(), this.securityInterceptor), this.handle); + new OperationHandler(operation.getInvoker(), operation.getId(), this.securityInterceptor), this.handle); } /** diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/HeapDumpWebEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/HeapDumpWebEndpoint.java index d1d4c00810e..ee39d39de24 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/HeapDumpWebEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/HeapDumpWebEndpoint.java @@ -36,7 +36,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.endpoint.Endpoint; -import org.springframework.boot.endpoint.EndpointType; +import org.springframework.boot.endpoint.EndpointDelivery; import org.springframework.boot.endpoint.ReadOperation; import org.springframework.boot.endpoint.web.WebEndpointResponse; import org.springframework.core.io.FileSystemResource; @@ -55,7 +55,7 @@ import org.springframework.util.ReflectionUtils; * @since 2.0.0 */ @ConfigurationProperties(prefix = "endpoints.heapdump") -@Endpoint(id = "heapdump", types = EndpointType.WEB) +@Endpoint(id = "heapdump", delivery = EndpointDelivery.WEB) public class HeapDumpWebEndpoint { private final long timeout; diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/LogFileWebEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/LogFileWebEndpoint.java index d82ee0c4af0..74a55e0fee4 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/LogFileWebEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/LogFileWebEndpoint.java @@ -23,7 +23,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.endpoint.Endpoint; -import org.springframework.boot.endpoint.EndpointType; +import org.springframework.boot.endpoint.EndpointDelivery; import org.springframework.boot.endpoint.ReadOperation; import org.springframework.boot.logging.LogFile; import org.springframework.core.env.Environment; @@ -39,7 +39,7 @@ import org.springframework.core.io.Resource; * @since 2.0.0 */ @ConfigurationProperties(prefix = "endpoints.logfile") -@Endpoint(id = "logfile", types = EndpointType.WEB) +@Endpoint(id = "logfile", delivery = EndpointDelivery.WEB) public class LogFileWebEndpoint { private static final Log logger = LogFactory.getLog(LogFileWebEndpoint.class); diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/ConditionalOnEnabledEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/ConditionalOnEnabledEndpointTests.java index e15e46251f8..3ae081eeeb3 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/ConditionalOnEnabledEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/ConditionalOnEnabledEndpointTests.java @@ -19,7 +19,7 @@ package org.springframework.boot.actuate.autoconfigure.endpoint; import org.junit.Test; import org.springframework.boot.endpoint.Endpoint; -import org.springframework.boot.endpoint.EndpointType; +import org.springframework.boot.endpoint.EndpointDelivery; import org.springframework.boot.endpoint.jmx.JmxEndpointExtension; import org.springframework.boot.endpoint.web.WebEndpointExtension; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -297,8 +297,8 @@ public class ConditionalOnEnabledEndpointTests { } - @Endpoint(id = "bar", types = { EndpointType.WEB, - EndpointType.JMX }, enabledByDefault = false) + @Endpoint(id = "bar", delivery = { EndpointDelivery.WEB, + EndpointDelivery.JMX }, enabledByDefault = false) static class BarEndpoint { } @@ -314,7 +314,7 @@ public class ConditionalOnEnabledEndpointTests { } - @Endpoint(id = "onlyweb", types = EndpointType.WEB) + @Endpoint(id = "onlyweb", delivery = EndpointDelivery.WEB) static class OnlyWebEndpoint { } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/EndpointEnablementProviderTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/EndpointEnablementProviderTests.java index 75441f990bc..91fa808ed27 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/EndpointEnablementProviderTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/support/EndpointEnablementProviderTests.java @@ -20,7 +20,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.springframework.boot.endpoint.EndpointType; +import org.springframework.boot.endpoint.EndpointDelivery; import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.mock.env.MockEnvironment; import org.springframework.util.ObjectUtils; @@ -41,7 +41,7 @@ public class EndpointEnablementProviderTests { public void cannotDetermineEnablementWithEmptyEndpoint() { this.thrown.expect(IllegalArgumentException.class); this.thrown.expectMessage("Endpoint id must have a value"); - determineEnablement(" ", true); + getEndpointEnablement(" ", true); } @Test @@ -49,289 +49,295 @@ public class EndpointEnablementProviderTests { this.thrown.expect(IllegalArgumentException.class); this.thrown.expectMessage("Endpoint id 'default' is a reserved value and cannot " + "be used by an endpoint"); - determineEnablement("default", true); + getEndpointEnablement("default", true); } @Test public void generalEnabledByDefault() { - validate(determineEnablement("foo", true), true, - "endpoint 'foo' is enabled by default"); + EndpointEnablement enablement = getEndpointEnablement("foo", true); + validate(enablement, true, "endpoint 'foo' is enabled by default"); } @Test public void generalDisabledViaSpecificProperty() { - validate(determineEnablement("foo", true, "endpoints.foo.enabled=false"), false, - "found property endpoints.foo.enabled"); + EndpointEnablement enablement = getEndpointEnablement("foo", true, + "endpoints.foo.enabled=false"); + validate(enablement, false, "found property endpoints.foo.enabled"); } @Test public void generalDisabledViaGeneralProperty() { - validate(determineEnablement("foo", true, "endpoints.default.enabled=false"), false, - "found property endpoints.default.enabled"); + EndpointEnablement enablement = getEndpointEnablement("foo", true, + "endpoints.default.enabled=false"); + validate(enablement, false, "found property endpoints.default.enabled"); } @Test public void generalEnabledOverrideViaSpecificProperty() { - validate( - determineEnablement("foo", true, "endpoints.default.enabled=false", - "endpoints.foo.enabled=true"), - true, "found property endpoints.foo.enabled"); + EndpointEnablement enablement = getEndpointEnablement("foo", true, + "endpoints.default.enabled=false", "endpoints.foo.enabled=true"); + validate(enablement, true, "found property endpoints.foo.enabled"); } @Test public void generalEnabledOverrideViaSpecificWebProperty() { - validate( - determineEnablement("foo", true, "endpoints.foo.enabled=false", - "endpoints.foo.web.enabled=true"), - true, "found property endpoints.foo.web.enabled"); + EndpointEnablement enablement = getEndpointEnablement("foo", true, + "endpoints.foo.enabled=false", "endpoints.foo.web.enabled=true"); + validate(enablement, true, "found property endpoints.foo.web.enabled"); } @Test public void generalEnabledOverrideViaSpecificJmxProperty() { - validate( - determineEnablement("foo", true, "endpoints.foo.enabled=false", - "endpoints.foo.jmx.enabled=true"), - true, "found property endpoints.foo.jmx.enabled"); + EndpointEnablement enablement = getEndpointEnablement("foo", true, + "endpoints.foo.enabled=false", "endpoints.foo.jmx.enabled=true"); + validate(enablement, true, "found property endpoints.foo.jmx.enabled"); } @Test public void generalEnabledOverrideViaSpecificAnyProperty() { - validate(determineEnablement("foo", true, "endpoints.foo.enabled=false", + validate(getEndpointEnablement("foo", true, "endpoints.foo.enabled=false", "endpoints.foo.web.enabled=false", "endpoints.foo.jmx.enabled=true"), true, "found property endpoints.foo.jmx.enabled"); } @Test public void generalEnabledOverrideViaGeneralWebProperty() { - validate( - determineEnablement("foo", true, "endpoints.default.enabled=false", - "endpoints.default.web.enabled=true"), - true, "found property endpoints.default.web.enabled"); + EndpointEnablement enablement = getEndpointEnablement("foo", true, + "endpoints.default.enabled=false", "endpoints.default.web.enabled=true"); + validate(enablement, true, "found property endpoints.default.web.enabled"); } @Test public void generalEnabledOverrideViaGeneralJmxProperty() { - validate( - determineEnablement("foo", true, "endpoints.default.enabled=false", - "endpoints.default.jmx.enabled=true"), - true, "found property endpoints.default.jmx.enabled"); + EndpointEnablement enablement = getEndpointEnablement("foo", true, + "endpoints.default.enabled=false", "endpoints.default.jmx.enabled=true"); + validate(enablement, true, "found property endpoints.default.jmx.enabled"); } @Test public void generalEnabledOverrideViaGeneralAnyProperty() { - validate(determineEnablement("foo", true, "endpoints.default.enabled=false", - "endpoints.default.web.enabled=false", "endpoints.default.jmx.enabled=true"), - true, "found property endpoints.default.jmx.enabled"); + EndpointEnablement enablement = getEndpointEnablement("foo", true, + "endpoints.default.enabled=false", "endpoints.default.web.enabled=false", + "endpoints.default.jmx.enabled=true"); + validate(enablement, true, "found property endpoints.default.jmx.enabled"); } @Test public void generalDisabledEvenWithEnabledGeneralProperties() { - validate( - determineEnablement("foo", true, "endpoints.default.enabled=true", - "endpoints.default.web.enabled=true", - "endpoints.default.jmx.enabled=true", "endpoints.foo.enabled=false"), - false, "found property endpoints.foo.enabled"); + EndpointEnablement enablement = getEndpointEnablement("foo", true, + "endpoints.default.enabled=true", "endpoints.default.web.enabled=true", + "endpoints.default.jmx.enabled=true", "endpoints.foo.enabled=false"); + validate(enablement, false, "found property endpoints.foo.enabled"); } @Test public void generalDisabledByDefaultWithAnnotationFlag() { - validate(determineEnablement("bar", false), false, - "endpoint 'bar' is disabled by default"); + EndpointEnablement enablement = getEndpointEnablement("bar", false); + validate(enablement, false, "endpoint 'bar' is disabled by default"); } @Test public void generalDisabledByDefaultWithAnnotationFlagEvenWithGeneralProperty() { - validate(determineEnablement("bar", false, "endpoints.default.enabled=true"), false, - "endpoint 'bar' is disabled by default"); + EndpointEnablement enablement = getEndpointEnablement("bar", false, + "endpoints.default.enabled=true"); + validate(enablement, false, "endpoint 'bar' is disabled by default"); } @Test public void generalDisabledByDefaultWithAnnotationFlagEvenWithGeneralWebProperty() { - validate(determineEnablement("bar", false, "endpoints.default.web.enabled=true"), - false, "endpoint 'bar' is disabled by default"); + EndpointEnablement enablement = getEndpointEnablement("bar", false, + "endpoints.default.web.enabled=true"); + validate(enablement, false, "endpoint 'bar' is disabled by default"); } @Test public void generalDisabledByDefaultWithAnnotationFlagEvenWithGeneralJmxProperty() { - validate(determineEnablement("bar", false, "endpoints.default.jmx.enabled=true"), - false, "endpoint 'bar' is disabled by default"); + EndpointEnablement enablement = getEndpointEnablement("bar", false, + "endpoints.default.jmx.enabled=true"); + validate(enablement, false, "endpoint 'bar' is disabled by default"); } @Test public void generalEnabledOverrideWithAndAnnotationFlagAndSpecificProperty() { - validate(determineEnablement("bar", false, "endpoints.bar.enabled=true"), true, - "found property endpoints.bar.enabled"); + EndpointEnablement enablement = getEndpointEnablement("bar", false, + "endpoints.bar.enabled=true"); + validate(enablement, true, "found property endpoints.bar.enabled"); } @Test public void generalEnabledOverrideWithAndAnnotationFlagAndSpecificWebProperty() { - validate(determineEnablement("bar", false, "endpoints.bar.web.enabled=true"), - true, "found property endpoints.bar.web.enabled"); + EndpointEnablement enablement = getEndpointEnablement("bar", false, + "endpoints.bar.web.enabled=true"); + validate(enablement, true, "found property endpoints.bar.web.enabled"); } @Test public void generalEnabledOverrideWithAndAnnotationFlagAndSpecificJmxProperty() { - validate(determineEnablement("bar", false, "endpoints.bar.jmx.enabled=true"), - true, "found property endpoints.bar.jmx.enabled"); + EndpointEnablement enablement = getEndpointEnablement("bar", false, + "endpoints.bar.jmx.enabled=true"); + validate(enablement, true, "found property endpoints.bar.jmx.enabled"); } @Test public void generalEnabledOverrideWithAndAnnotationFlagAndAnyProperty() { - validate( - determineEnablement("bar", false, "endpoints.bar.web.enabled=false", - "endpoints.bar.jmx.enabled=true"), - true, "found property endpoints.bar.jmx.enabled"); + EndpointEnablement enablement = getEndpointEnablement("bar", false, + "endpoints.bar.web.enabled=false", "endpoints.bar.jmx.enabled=true"); + validate(enablement, true, "found property endpoints.bar.jmx.enabled"); } @Test public void specificEnabledByDefault() { - validate(determineEnablement("foo", true, EndpointType.JMX), true, - "endpoint 'foo' (jmx) is enabled by default"); + EndpointEnablement enablement = getEndpointEnablement("foo", true, + EndpointDelivery.JMX); + validate(enablement, true, "endpoint 'foo' (jmx) is enabled by default"); } @Test public void specificDisabledViaEndpointProperty() { - validate( - determineEnablement("foo", true, EndpointType.WEB, - "endpoints.foo.enabled=false"), - false, "found property endpoints.foo.enabled"); + EndpointEnablement enablement = getEndpointEnablement("foo", true, + EndpointDelivery.WEB, "endpoints.foo.enabled=false"); + validate(enablement, false, "found property endpoints.foo.enabled"); } @Test public void specificDisabledViaTechProperty() { - validate( - determineEnablement("foo", true, EndpointType.WEB, - "endpoints.foo.web.enabled=false"), - false, "found property endpoints.foo.web.enabled"); + EndpointEnablement enablement = getEndpointEnablement("foo", true, + EndpointDelivery.WEB, "endpoints.foo.web.enabled=false"); + validate(enablement, false, "found property endpoints.foo.web.enabled"); } @Test public void specificNotDisabledViaUnrelatedTechProperty() { - validate( - determineEnablement("foo", true, EndpointType.JMX, - "endpoints.foo.web.enabled=false"), - true, "endpoint 'foo' (jmx) is enabled by default"); + EndpointEnablement enablement = getEndpointEnablement("foo", true, + EndpointDelivery.JMX, "endpoints.foo.web.enabled=false"); + validate(enablement, true, "endpoint 'foo' (jmx) is enabled by default"); } @Test public void specificDisabledViaGeneralProperty() { - validate( - determineEnablement("foo", true, EndpointType.JMX, - "endpoints.default.enabled=false"), - false, "found property endpoints.default.enabled"); + EndpointEnablement enablement = getEndpointEnablement("foo", true, + EndpointDelivery.JMX, "endpoints.default.enabled=false"); + validate(enablement, false, "found property endpoints.default.enabled"); } @Test public void specificEnabledOverrideViaEndpointProperty() { - validate( - determineEnablement("foo", true, EndpointType.WEB, - "endpoints.default.enabled=false", "endpoints.foo.enabled=true"), - true, "found property endpoints.foo.enabled"); + EndpointEnablement enablement = getEndpointEnablement("foo", true, + EndpointDelivery.WEB, "endpoints.default.enabled=false", + "endpoints.foo.enabled=true"); + validate(enablement, true, "found property endpoints.foo.enabled"); } @Test public void specificEnabledOverrideViaTechProperty() { - validate( - determineEnablement("foo", true, EndpointType.WEB, - "endpoints.foo.enabled=false", "endpoints.foo.web.enabled=true"), - true, "found property endpoints.foo.web.enabled"); + EndpointEnablement enablement = getEndpointEnablement("foo", true, + EndpointDelivery.WEB, "endpoints.foo.enabled=false", + "endpoints.foo.web.enabled=true"); + validate(enablement, true, "found property endpoints.foo.web.enabled"); } @Test public void specificEnabledOverrideHasNotEffectWithUnrelatedTechProperty() { - validate( - determineEnablement("foo", true, EndpointType.WEB, - "endpoints.foo.enabled=false", "endpoints.foo.jmx.enabled=true"), - false, "found property endpoints.foo.enabled"); + EndpointEnablement enablement = getEndpointEnablement("foo", true, + EndpointDelivery.WEB, "endpoints.foo.enabled=false", + "endpoints.foo.jmx.enabled=true"); + validate(enablement, false, "found property endpoints.foo.enabled"); } @Test public void specificEnabledOverrideViaGeneralWebProperty() { - validate( - determineEnablement("foo", true, EndpointType.WEB, - "endpoints.default.enabled=false", "endpoints.default.web.enabled=true"), - true, "found property endpoints.default.web.enabled"); + EndpointEnablement enablement = getEndpointEnablement("foo", true, + EndpointDelivery.WEB, "endpoints.default.enabled=false", + "endpoints.default.web.enabled=true"); + validate(enablement, true, "found property endpoints.default.web.enabled"); } @Test public void specificEnabledOverrideHasNoEffectWithUnrelatedTechProperty() { validate( - determineEnablement("foo", true, EndpointType.JMX, + getEndpointEnablement("foo", true, EndpointDelivery.JMX, "endpoints.default.enabled=false", "endpoints.default.web.enabled=true"), false, "found property endpoints.default.enabled"); } @Test public void specificDisabledWithEndpointPropertyEvenWithEnabledGeneralProperties() { - validate( - determineEnablement("foo", true, EndpointType.WEB, - "endpoints.default.enabled=true", "endpoints.default.web.enabled=true", - "endpoints.default.jmx.enabled=true", "endpoints.foo.enabled=false"), - false, "found property endpoints.foo.enabled"); + EndpointEnablement enablement = getEndpointEnablement("foo", true, + EndpointDelivery.WEB, "endpoints.default.enabled=true", + "endpoints.default.web.enabled=true", "endpoints.default.jmx.enabled=true", + "endpoints.foo.enabled=false"); + validate(enablement, false, "found property endpoints.foo.enabled"); } @Test public void specificDisabledWithTechPropertyEvenWithEnabledGeneralProperties() { - validate( - determineEnablement("foo", true, EndpointType.WEB, - "endpoints.default.enabled=true", "endpoints.default.web.enabled=true", - "endpoints.default.jmx.enabled=true", "endpoints.foo.enabled=true", - "endpoints.foo.web.enabled=false"), - false, "found property endpoints.foo.web.enabled"); + EndpointEnablement enablement = getEndpointEnablement("foo", true, + EndpointDelivery.WEB, "endpoints.default.enabled=true", + "endpoints.default.web.enabled=true", "endpoints.default.jmx.enabled=true", + "endpoints.foo.enabled=true", "endpoints.foo.web.enabled=false"); + validate(enablement, false, "found property endpoints.foo.web.enabled"); } @Test public void specificDisabledByDefaultWithAnnotationFlag() { - validate(determineEnablement("bar", false, EndpointType.WEB), false, - "endpoint 'bar' (web) is disabled by default"); + EndpointEnablement enablement = getEndpointEnablement("bar", false, + EndpointDelivery.WEB); + validate(enablement, false, "endpoint 'bar' (web) is disabled by default"); } @Test public void specificDisabledByDefaultWithAnnotationFlagEvenWithGeneralProperty() { - validate( - determineEnablement("bar", false, EndpointType.WEB, - "endpoints.default.enabled=true"), - false, "endpoint 'bar' (web) is disabled by default"); + EndpointEnablement enablement = getEndpointEnablement("bar", false, + EndpointDelivery.WEB, "endpoints.default.enabled=true"); + validate(enablement, false, "endpoint 'bar' (web) is disabled by default"); } @Test public void specificDisabledByDefaultWithAnnotationFlagEvenWithGeneralWebProperty() { - validate( - determineEnablement("bar", false, EndpointType.WEB, - "endpoints.default.web.enabled=true"), - false, "endpoint 'bar' (web) is disabled by default"); + EndpointEnablement enablement = getEndpointEnablement("bar", false, + EndpointDelivery.WEB, "endpoints.default.web.enabled=true"); + validate(enablement, false, "endpoint 'bar' (web) is disabled by default"); } @Test public void specificDisabledByDefaultWithAnnotationFlagEvenWithGeneralJmxProperty() { - validate( - determineEnablement("bar", false, EndpointType.WEB, - "endpoints.default.jmx.enabled=true"), - false, "endpoint 'bar' (web) is disabled by default"); + EndpointEnablement enablement = getEndpointEnablement("bar", false, + EndpointDelivery.WEB, "endpoints.default.jmx.enabled=true"); + validate(enablement, false, "endpoint 'bar' (web) is disabled by default"); } @Test public void specificEnabledOverrideWithAndAnnotationFlagAndEndpointProperty() { - validate( - determineEnablement("bar", false, EndpointType.WEB, - "endpoints.bar.enabled=true"), - true, "found property endpoints.bar.enabled"); + EndpointEnablement enablement = getEndpointEnablement("bar", false, + EndpointDelivery.WEB, "endpoints.bar.enabled=true"); + validate(enablement, true, "found property endpoints.bar.enabled"); } @Test public void specificEnabledOverrideWithAndAnnotationFlagAndTechProperty() { - validate( - determineEnablement("bar", false, EndpointType.WEB, - "endpoints.bar.web.enabled=true"), - true, "found property endpoints.bar.web.enabled"); + EndpointEnablement enablement = getEndpointEnablement("bar", false, + EndpointDelivery.WEB, "endpoints.bar.web.enabled=true"); + validate(enablement, true, "found property endpoints.bar.web.enabled"); } @Test public void specificEnabledOverrideWithAndAnnotationFlagHasNoEffectWithUnrelatedTechProperty() { - validate( - determineEnablement("bar", false, EndpointType.WEB, - "endpoints.bar.jmx.enabled=true"), - false, "endpoint 'bar' (web) is disabled by default"); + EndpointEnablement enablement = getEndpointEnablement("bar", false, + EndpointDelivery.WEB, "endpoints.bar.jmx.enabled=true"); + validate(enablement, false, "endpoint 'bar' (web) is disabled by default"); + } + + private EndpointEnablement getEndpointEnablement(String id, boolean enabledByDefault, + String... environment) { + return getEndpointEnablement(id, enabledByDefault, null, environment); + } + + private EndpointEnablement getEndpointEnablement(String id, boolean enabledByDefault, + EndpointDelivery delivery, String... environment) { + MockEnvironment env = new MockEnvironment(); + TestPropertyValues.of(environment).applyTo(env); + EndpointEnablementProvider provider = new EndpointEnablementProvider(env); + return provider.getEndpointEnablement(id, enabledByDefault, delivery); } private void validate(EndpointEnablement enablement, boolean enabled, @@ -343,17 +349,4 @@ public class EndpointEnablementProviderTests { } } - private EndpointEnablement determineEnablement(String id, boolean enabledByDefault, - String... environment) { - return determineEnablement(id, enabledByDefault, null, environment); - } - - private EndpointEnablement determineEnablement(String id, boolean enabledByDefault, - EndpointType type, String... environment) { - MockEnvironment env = new MockEnvironment(); - TestPropertyValues.of(environment).applyTo(env); - EndpointEnablementProvider provider = new EndpointEnablementProvider(env); - return provider.getEndpointEnablement(id, enabledByDefault, type); - } - } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpointTests.java index 5c0d425359c..710180a3a0b 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpointTests.java @@ -22,7 +22,7 @@ import java.util.Map; import org.junit.Test; import org.springframework.boot.endpoint.EndpointInfo; -import org.springframework.boot.endpoint.EndpointOperationType; +import org.springframework.boot.endpoint.OperationType; import org.springframework.boot.endpoint.web.OperationRequestPredicate; import org.springframework.boot.endpoint.web.WebEndpointHttpMethod; import org.springframework.boot.endpoint.web.WebEndpointOperation; @@ -136,7 +136,7 @@ public class RequestMappingEndpointTests { WebEndpointHttpMethod.GET, Collections.singletonList("application/json"), Collections.singletonList("application/json")); WebEndpointOperation operation = new WebEndpointOperation( - EndpointOperationType.READ, (arguments) -> "Invoked", true, + OperationType.READ, (arguments) -> "Invoked", true, requestPredicate, "test"); WebEndpointServletHandlerMapping mapping = new WebEndpointServletHandlerMapping( "application", Collections.singleton(new EndpointInfo<>("test", true, diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/AnnotationEndpointDiscoverer.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/AnnotationEndpointDiscoverer.java index 94eb2d9554b..4a47c0d802e 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/AnnotationEndpointDiscoverer.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/AnnotationEndpointDiscoverer.java @@ -19,10 +19,10 @@ package org.springframework.boot.endpoint; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.function.Consumer; @@ -32,6 +32,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.core.MethodIntrospector; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.util.Assert; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.ObjectUtils; @@ -45,7 +46,7 @@ import org.springframework.util.ObjectUtils; * @author Stephane Nicoll * @since 2.0.0 */ -public abstract class AnnotationEndpointDiscoverer +public abstract class AnnotationEndpointDiscoverer implements EndpointDiscoverer { private final ApplicationContext applicationContext; @@ -69,15 +70,15 @@ public abstract class AnnotationEndpointDiscoverer> discoverEndpointsWithExtension( - Class extensionType, EndpointType endpointType) { - Map, EndpointInfo> endpoints = discoverGenericEndpoints(endpointType); + protected Collection> discoverEndpoints( + Class extensionType, EndpointDelivery delivery) { + Map, EndpointInfo> endpoints = discoverEndpoints(delivery); Map, EndpointExtensionInfo> extensions = discoverExtensions(endpoints, - extensionType, endpointType); + extensionType, delivery); Collection> result = new ArrayList<>(); endpoints.forEach((endpointClass, endpointInfo) -> { EndpointExtensionInfo extension = extensions.remove(endpointClass); @@ -86,169 +87,156 @@ public abstract class AnnotationEndpointDiscoverer createDescriptor(Class endpointType, - EndpointInfo endpoint, EndpointExtensionInfo extension) { - Map, List> endpointOperations = indexOperations( - endpoint.getId(), endpointType, endpoint.getOperations()); + private Map, EndpointInfo> discoverEndpoints(EndpointDelivery delivery) { + String[] beanNames = this.applicationContext + .getBeanNamesForAnnotation(Endpoint.class); + Map, EndpointInfo> endpoints = new LinkedHashMap<>(); + Map> endpointsById = new LinkedHashMap<>(); + for (String beanName : beanNames) { + Class beanType = this.applicationContext.getType(beanName); + AnnotationAttributes attributes = AnnotatedElementUtils + .findMergedAnnotationAttributes(beanType, Endpoint.class, true, true); + if (isDeliveredOver(attributes, delivery)) { + EndpointInfo info = createEndpointInfo(beanName, beanType, attributes); + EndpointInfo previous = endpointsById.putIfAbsent(info.getId(), info); + Assert.state(previous == null, () -> "Found two endpoints with the id '" + + info.getId() + "': " + info + " and " + previous); + endpoints.put(beanType, info); + } + } + return endpoints; + } + + private EndpointInfo createEndpointInfo(String beanName, Class beanType, + AnnotationAttributes attributes) { + String id = attributes.getString("id"); + boolean enabledByDefault = attributes.getBoolean("enabledByDefault"); + Map operations = discoverOperations(id, beanName, beanType); + return new EndpointInfo<>(id, enabledByDefault, operations.values()); + } + + private Map, EndpointExtensionInfo> discoverExtensions( + Map, EndpointInfo> endpoints, + Class extensionType, EndpointDelivery delivery) { + if (extensionType == null) { + return Collections.emptyMap(); + } + String[] beanNames = this.applicationContext + .getBeanNamesForAnnotation(extensionType); + Map, EndpointExtensionInfo> extensions = new HashMap<>(); + for (String beanName : beanNames) { + Class beanType = this.applicationContext.getType(beanName); + Class endpointType = getEndpointType(extensionType, beanType); + AnnotationAttributes endpointAttributes = AnnotatedElementUtils + .getMergedAnnotationAttributes(endpointType, Endpoint.class); + Assert.state(isDeliveredOver(endpointAttributes, delivery), + "Invalid extension " + beanType.getName() + "': endpoint '" + + endpointType.getName() + + "' does not support such extension"); + EndpointInfo info = getEndpointInfo(endpoints, beanType, endpointType); + Map operations = discoverOperations(info.getId(), beanName, + beanType); + EndpointExtensionInfo extension = new EndpointExtensionInfo<>(beanType, + operations.values()); + EndpointExtensionInfo previous = extensions.putIfAbsent(endpointType, + extension); + Assert.state(previous == null, + () -> "Found two extensions for the same endpoint '" + + endpointType.getName() + "': " + + extension.getExtensionType().getName() + " and " + + previous.getExtensionType().getName()); + } + return extensions; + + } + + private EndpointInfo getEndpointInfo(Map, EndpointInfo> endpoints, + Class beanType, Class endpointClass) { + EndpointInfo endpoint = endpoints.get(endpointClass); + Assert.state(endpoint != null, "Invalid extension '" + beanType.getName() + + "': no endpoint found with type '" + endpointClass.getName() + "'"); + return endpoint; + } + + private Class getEndpointType(Class extensionType, + Class beanType) { + AnnotationAttributes attributes = AnnotatedElementUtils + .getMergedAnnotationAttributes(beanType, extensionType); + return (Class) attributes.get("endpoint"); + } + + private EndpointInfoDescriptor createDescriptor(Class type, + EndpointInfo info, EndpointExtensionInfo extension) { + Map, List> operations = indexOperations(info.getId(), type, + info.getOperations()); if (extension != null) { - endpointOperations.putAll(indexOperations(endpoint.getId(), - extension.getEndpointExtensionType(), extension.getOperations())); - return new EndpointInfoDescriptor<>(mergeEndpoint(endpoint, extension), - endpointOperations); - } - else { - return new EndpointInfoDescriptor<>(endpoint, endpointOperations); + operations.putAll(indexOperations(info.getId(), extension.getExtensionType(), + extension.getOperations())); + return new EndpointInfoDescriptor<>(mergeEndpoint(info, extension), + operations); } + return new EndpointInfoDescriptor<>(info, operations); } private EndpointInfo mergeEndpoint(EndpointInfo endpoint, EndpointExtensionInfo extension) { Map operations = new HashMap<>(); - Consumer operationConsumer = (operation) -> operations + Consumer consumer = (operation) -> operations .put(this.operationKeyFactory.apply(operation), operation); - endpoint.getOperations().forEach(operationConsumer); - extension.getOperations().forEach(operationConsumer); + endpoint.getOperations().forEach(consumer); + extension.getOperations().forEach(consumer); return new EndpointInfo<>(endpoint.getId(), endpoint.isEnabledByDefault(), operations.values()); } private Map, List> indexOperations(String endpointId, Class target, Collection operations) { - LinkedMultiValueMap, T> operationByKey = new LinkedMultiValueMap<>(); - operations - .forEach( - (operation) -> operationByKey.add( - new OperationKey<>(endpointId, target, - this.operationKeyFactory.apply(operation)), - operation)); - return operationByKey; + LinkedMultiValueMap, T> result = new LinkedMultiValueMap<>(); + operations.forEach((operation) -> { + K key = this.operationKeyFactory.apply(operation); + result.add(new OperationKey<>(endpointId, target, key), operation); + }); + return result; } - private Map, EndpointInfo> discoverGenericEndpoints( - EndpointType endpointType) { - String[] endpointBeanNames = this.applicationContext - .getBeanNamesForAnnotation(Endpoint.class); - Map> endpointsById = new HashMap<>(); - Map, EndpointInfo> endpointsByClass = new HashMap<>(); - for (String beanName : endpointBeanNames) { - Class beanType = this.applicationContext.getType(beanName); - AnnotationAttributes endpointAttributes = AnnotatedElementUtils - .findMergedAnnotationAttributes(beanType, Endpoint.class, true, true); - String endpointId = endpointAttributes.getString("id"); - if (matchEndpointType(endpointAttributes, endpointType)) { - EndpointInfo endpointInfo = createEndpointInfo(endpointsById, beanName, - beanType, endpointAttributes, endpointId); - endpointsByClass.put(beanType, endpointInfo); - } - } - return endpointsByClass; - } - - private EndpointInfo createEndpointInfo(Map> endpointsById, - String beanName, Class beanType, AnnotationAttributes endpointAttributes, - String endpointId) { - Map operationMethods = discoverOperations(endpointId, beanName, - beanType); - EndpointInfo endpointInfo = new EndpointInfo<>(endpointId, - endpointAttributes.getBoolean("enabledByDefault"), - operationMethods.values()); - EndpointInfo previous = endpointsById.putIfAbsent(endpointInfo.getId(), - endpointInfo); - if (previous != null) { - throw new IllegalStateException("Found two endpoints with the id '" - + endpointInfo.getId() + "': " + endpointInfo + " and " + previous); - } - return endpointInfo; - } - - private Map, EndpointExtensionInfo> discoverExtensions( - Map, EndpointInfo> endpoints, - Class extensionType, EndpointType endpointType) { - if (extensionType == null) { - return Collections.emptyMap(); - } - String[] extensionBeanNames = this.applicationContext - .getBeanNamesForAnnotation(extensionType); - Map, EndpointExtensionInfo> extensionsByEndpoint = new HashMap<>(); - for (String beanName : extensionBeanNames) { - Class beanType = this.applicationContext.getType(beanName); - AnnotationAttributes extensionAttributes = AnnotatedElementUtils - .getMergedAnnotationAttributes(beanType, extensionType); - Class endpointClass = (Class) extensionAttributes.get("endpoint"); - AnnotationAttributes endpointAttributes = AnnotatedElementUtils - .getMergedAnnotationAttributes(endpointClass, Endpoint.class); - if (!matchEndpointType(endpointAttributes, endpointType)) { - throw new IllegalStateException(String.format( - "Invalid extension %s': " - + "endpoint '%s' does not support such extension", - beanType.getName(), endpointClass.getName())); - } - EndpointInfo endpoint = endpoints.get(endpointClass); - if (endpoint == null) { - throw new IllegalStateException(String.format( - "Invalid extension '%s': no endpoint found with type '%s'", - beanType.getName(), endpointClass.getName())); - } - Map operationMethods = discoverOperations(endpoint.getId(), - beanName, beanType); - EndpointExtensionInfo extension = new EndpointExtensionInfo<>(beanType, - operationMethods.values()); - EndpointExtensionInfo previous = extensionsByEndpoint - .putIfAbsent(endpointClass, extension); - if (previous != null) { - throw new IllegalStateException( - "Found two extensions for the same endpoint '" - + endpointClass.getName() + "': " - + extension.getEndpointExtensionType().getName() + " and " - + previous.getEndpointExtensionType().getName()); - } - } - return extensionsByEndpoint; - } - - private boolean matchEndpointType(AnnotationAttributes endpointAttributes, - EndpointType endpointType) { - if (endpointType == null) { + private boolean isDeliveredOver(AnnotationAttributes attributes, + EndpointDelivery delivery) { + if (delivery == null) { return true; } - Object types = endpointAttributes.get("types"); - if (ObjectUtils.isEmpty(types)) { - return true; - } - return Arrays.stream((EndpointType[]) types) - .anyMatch((t) -> t.equals(endpointType)); + EndpointDelivery[] supported = (EndpointDelivery[]) attributes.get("delivery"); + return ObjectUtils.isEmpty(supported) + || ObjectUtils.containsElement(supported, delivery); } - private Map discoverOperations(String endpointId, String beanName, - Class beanType) { - return MethodIntrospector.selectMethods(beanType, + private Map discoverOperations(String id, String name, Class type) { + return MethodIntrospector.selectMethods(type, (MethodIntrospector.MetadataLookup) ( - method) -> createOperationIfPossible(endpointId, beanName, - method)); + method) -> createOperationIfPossible(id, name, method)); } private T createOperationIfPossible(String endpointId, String beanName, Method method) { T readOperation = createReadOperationIfPossible(endpointId, beanName, method); - return readOperation != null ? readOperation - : createWriteOperationIfPossible(endpointId, beanName, method); + return (readOperation != null ? readOperation + : createWriteOperationIfPossible(endpointId, beanName, method)); } private T createReadOperationIfPossible(String endpointId, String beanName, Method method) { return createOperationIfPossible(endpointId, beanName, method, - ReadOperation.class, EndpointOperationType.READ); + ReadOperation.class, OperationType.READ); } private T createWriteOperationIfPossible(String endpointId, String beanName, Method method) { return createOperationIfPossible(endpointId, beanName, method, - WriteOperation.class, EndpointOperationType.WRITE); + WriteOperation.class, OperationType.WRITE); } private T createOperationIfPossible(String endpointId, String beanName, Method method, Class operationAnnotation, - EndpointOperationType operationType) { + OperationType operationType) { AnnotationAttributes operationAttributes = AnnotatedElementUtils .getMergedAnnotationAttributes(method, operationAnnotation); if (operationAttributes == null) { @@ -262,9 +250,9 @@ public abstract class AnnotationEndpointDiscoverer 0 - && operationType == EndpointOperationType.READ + && operationType == OperationType.READ && method.getParameters().length == 0) { return cachingConfiguration.getTimeToLive(); } @@ -272,13 +260,13 @@ public abstract class AnnotationEndpointDiscoverer the {@link EndpointOperation} type + * @param the {@link Operation} type */ @FunctionalInterface - protected interface EndpointOperationFactory { + protected interface EndpointOperationFactory { /** * Creates an {@code EndpointOperation} for an operation on an endpoint. @@ -291,8 +279,8 @@ public abstract class AnnotationEndpointDiscoverer the type of the operation */ - private static final class EndpointExtensionInfo { + private static final class EndpointExtensionInfo { - private final Class endpointExtensionType; + private final Class extensionType; private final Collection operations; - private EndpointExtensionInfo(Class endpointExtensionType, - Collection operations) { - this.endpointExtensionType = endpointExtensionType; + private EndpointExtensionInfo(Class extensionType, Collection operations) { + this.extensionType = extensionType; this.operations = operations; } - private Class getEndpointExtensionType() { - return this.endpointExtensionType; + private Class getExtensionType() { + return this.extensionType; } private Collection getOperations() { @@ -328,7 +315,7 @@ public abstract class AnnotationEndpointDiscoverer the type of the operation * @param the type of the operation key */ - protected static class EndpointInfoDescriptor { + protected static class EndpointInfoDescriptor { private final EndpointInfo endpointInfo; @@ -377,22 +364,18 @@ public abstract class AnnotationEndpointDiscoverer that = (OperationKey) o; - - if (!this.endpointId.equals(that.endpointId)) { - return false; - } - if (!this.endpointType.equals(that.endpointType)) { - return false; - } - return this.key.equals(that.key); + OperationKey other = (OperationKey) o; + Boolean result = true; + result = result && this.endpointId.equals(other.endpointId); + result = result && this.endpointType.equals(other.endpointType); + result = result && this.key.equals(other.key); + return result; } @Override diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/DefaultEndpointPathResolver.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/DefaultEndpointPathResolver.java index 703d9babddc..919ec4bed6e 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/DefaultEndpointPathResolver.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/DefaultEndpointPathResolver.java @@ -17,8 +17,8 @@ package org.springframework.boot.endpoint; /** - * {@link EndpointPathResolver} implementation that does not support - * resolving endpoint paths. + * {@link EndpointPathResolver} implementation that does not support resolving endpoint + * paths. * * @author Madhura Bhave * @since 2.0.0 @@ -31,4 +31,3 @@ public class DefaultEndpointPathResolver implements EndpointPathResolver { } } - diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/Endpoint.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/Endpoint.java index 5483ecadf17..e98f8b97858 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/Endpoint.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/Endpoint.java @@ -41,11 +41,11 @@ public @interface Endpoint { String id(); /** - * Defines the endpoint {@link EndpointType types} that should be exposed. By default, - * all types are exposed. - * @return the endpoint types to expose + * Defines the {@link EndpointDelivery delivery technologies} over which the + * endpoint should be delivered over. By default, all technologies are supported. + * @return the supported endpoint delivery technologies */ - EndpointType[] types() default {}; + EndpointDelivery[] delivery() default {}; /** * Whether or not the endpoint is enabled by default. diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/EndpointType.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/EndpointDelivery.java similarity index 86% rename from spring-boot/src/main/java/org/springframework/boot/endpoint/EndpointType.java rename to spring-boot/src/main/java/org/springframework/boot/endpoint/EndpointDelivery.java index 8567f273af5..df75b3e4ef6 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/EndpointType.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/EndpointDelivery.java @@ -17,12 +17,12 @@ package org.springframework.boot.endpoint; /** - * An enumeration of the available {@link Endpoint} types. + * An enumeration of the available {@link Endpoint} delivery technologies. * * @author Stephane Nicoll * @since 2.0.0 */ -public enum EndpointType { +public enum EndpointDelivery { /** * Expose the endpoint as a JMX MBean. @@ -36,11 +36,12 @@ public enum EndpointType { private final boolean enabledByDefault; - EndpointType(boolean enabledByDefault) { + EndpointDelivery(boolean enabledByDefault) { this.enabledByDefault = enabledByDefault; } public boolean isEnabledByDefault() { return this.enabledByDefault; } + } diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/EndpointDiscoverer.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/EndpointDiscoverer.java index 0013da9a028..969417de69e 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/EndpointDiscoverer.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/EndpointDiscoverer.java @@ -27,7 +27,7 @@ import java.util.Collection; * @since 2.0.0 */ @FunctionalInterface -public interface EndpointDiscoverer { +public interface EndpointDiscoverer { /** * Perform endpoint discovery. diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/EndpointInfo.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/EndpointInfo.java index 50a852bb6f4..00fd684c74a 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/EndpointInfo.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/EndpointInfo.java @@ -25,7 +25,7 @@ import java.util.Collection; * @author Andy Wilkinson * @since 2.0.0 */ -public class EndpointInfo { +public class EndpointInfo { private final String id; diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/EndpointOperation.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/Operation.java similarity index 79% rename from spring-boot/src/main/java/org/springframework/boot/endpoint/EndpointOperation.java rename to spring-boot/src/main/java/org/springframework/boot/endpoint/Operation.java index f4583e05daf..50675aa0830 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/EndpointOperation.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/Operation.java @@ -22,11 +22,11 @@ package org.springframework.boot.endpoint; * @author Andy Wilkinson * @since 2.0.0 */ -public class EndpointOperation { +public class Operation { - private final EndpointOperationType type; + private final OperationType type; - private final OperationInvoker operationInvoker; + private final OperationInvoker invoker; private final boolean blocking; @@ -37,18 +37,18 @@ public class EndpointOperation { * @param operationInvoker used to perform the operation * @param blocking whether or not this is a blocking operation */ - public EndpointOperation(EndpointOperationType type, + public Operation(OperationType type, OperationInvoker operationInvoker, boolean blocking) { this.type = type; - this.operationInvoker = operationInvoker; + this.invoker = operationInvoker; this.blocking = blocking; } /** - * Returns the {@link EndpointOperationType type} of the operation. + * Returns the {@link OperationType type} of the operation. * @return the type */ - public EndpointOperationType getType() { + public OperationType getType() { return this.type; } @@ -57,8 +57,8 @@ public class EndpointOperation { * operation. * @return the operation invoker */ - public OperationInvoker getOperationInvoker() { - return this.operationInvoker; + public OperationInvoker getInvoker() { + return this.invoker; } /** diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/EndpointOperationType.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/OperationType.java similarity index 96% rename from spring-boot/src/main/java/org/springframework/boot/endpoint/EndpointOperationType.java rename to spring-boot/src/main/java/org/springframework/boot/endpoint/OperationType.java index 1cfabdfcacb..6d1ae90d7bd 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/EndpointOperationType.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/OperationType.java @@ -22,7 +22,7 @@ package org.springframework.boot.endpoint; * @author Andy Wilkinson * @since 2.0.0 */ -public enum EndpointOperationType { +public enum OperationType { /** * A read operation. diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/ParameterMappingException.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/ParameterMappingException.java index c7371217555..4c76cee4be8 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/ParameterMappingException.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/ParameterMappingException.java @@ -47,7 +47,6 @@ public class ParameterMappingException extends RuntimeException { /** * Returns the input that was to be mapped. - * * @return the input */ public Object getInput() { @@ -56,7 +55,6 @@ public class ParameterMappingException extends RuntimeException { /** * Returns the type to be mapped to. - * * @return the type */ public Class getType() { diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/ReflectiveOperationInvoker.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/ReflectiveOperationInvoker.java index ded4079bc8e..947245feec0 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/ReflectiveOperationInvoker.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/ReflectiveOperationInvoker.java @@ -42,7 +42,6 @@ public class ReflectiveOperationInvoker implements OperationInvoker { * Creates a new {code ReflectiveOperationInvoker} that will invoke the given * {@code method} on the given {@code target}. The given {@code parameterMapper} will * be used to map parameters to the required types. - * * @param parameterMapper the parameter mapper * @param target the target of the reflective call * @param method the method to call diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/EndpointMBean.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/EndpointMBean.java index bedb1e63ca2..c5c37d97ee6 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/EndpointMBean.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/EndpointMBean.java @@ -74,16 +74,12 @@ public class EndpointMBean implements DynamicMBean { @Override public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException { - JmxEndpointOperation operationInfo = this.endpointInfo.getOperations() + JmxEndpointOperation operation = this.endpointInfo.getOperations() .get(actionName); - if (operationInfo != null) { - Map arguments = new HashMap<>(); - List parameters = operationInfo - .getParameters(); - for (int i = 0; i < params.length; i++) { - arguments.put(parameters.get(i).getName(), params[i]); - } - Object result = operationInfo.getOperationInvoker().invoke(arguments); + if (operation != null) { + Map arguments = getArguments(params, + operation.getParameters()); + Object result = operation.getInvoker().invoke(arguments); if (REACTOR_PRESENT) { result = ReactiveHandler.handle(result); } @@ -94,6 +90,15 @@ public class EndpointMBean implements DynamicMBean { this.endpointInfo.getEndpointId(), actionName))); } + private Map getArguments(Object[] params, + List parameters) { + Map arguments = new HashMap<>(); + for (int i = 0; i < params.length; i++) { + arguments.put(parameters.get(i).getName(), params[i]); + } + return arguments; + } + @Override public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException { diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/EndpointMBeanInfo.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/EndpointMBeanInfo.java index d457dbd2e44..d97e5463c24 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/EndpointMBeanInfo.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/EndpointMBeanInfo.java @@ -21,11 +21,11 @@ import java.util.Map; import javax.management.MBeanInfo; import org.springframework.boot.endpoint.EndpointInfo; -import org.springframework.boot.endpoint.EndpointOperation; +import org.springframework.boot.endpoint.Operation; /** * The {@link MBeanInfo} for a particular {@link EndpointInfo endpoint}. Maps operation - * names to an {@link EndpointOperation}. + * names to an {@link Operation}. * * @author Stephane Nicoll * @since 2.0.0 diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/EndpointMBeanInfoAssembler.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/EndpointMBeanInfoAssembler.java index 237e97641c4..be2e919eb2e 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/EndpointMBeanInfoAssembler.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/EndpointMBeanInfoAssembler.java @@ -31,7 +31,7 @@ import javax.management.modelmbean.ModelMBeanNotificationInfo; import javax.management.modelmbean.ModelMBeanOperationInfo; import org.springframework.boot.endpoint.EndpointInfo; -import org.springframework.boot.endpoint.EndpointOperationType; +import org.springframework.boot.endpoint.OperationType; /** * Gathers the management operations of a particular {@link EndpointInfo endpoint}. @@ -61,7 +61,6 @@ class EndpointMBeanInfoAssembler { .toArray(new ModelMBeanOperationInfo[] {}); Map operationsInfo = new LinkedHashMap<>(); operationsMapping.forEach((name, t) -> operationsInfo.put(name, t.operation)); - MBeanInfo info = new ModelMBeanInfoSupport(EndpointMBean.class.getName(), getDescription(endpointInfo), new ModelMBeanAttributeInfo[0], new ModelMBeanConstructorInfo[0], operationsMBeanInfo, @@ -100,11 +99,11 @@ class EndpointMBeanInfoAssembler { .toArray(new MBeanParameterInfo[parameterInfos.size()]))); } - private int mapOperationType(EndpointOperationType type) { - if (type == EndpointOperationType.READ) { + private int mapOperationType(OperationType type) { + if (type == OperationType.READ) { return MBeanOperationInfo.INFO; } - if (type == EndpointOperationType.WRITE) { + if (type == OperationType.WRITE) { return MBeanOperationInfo.ACTION; } return MBeanOperationInfo.UNKNOWN; diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/EndpointMBeanRegistrar.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/EndpointMBeanRegistrar.java index 887ee965068..b04de7ae134 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/EndpointMBeanRegistrar.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/EndpointMBeanRegistrar.java @@ -68,24 +68,21 @@ public class EndpointMBeanRegistrar { Assert.notNull(endpoint, "Endpoint must not be null"); try { if (logger.isDebugEnabled()) { - logger.debug(String.format( - "Registering endpoint with id '%s' to " + "the JMX domain", - endpoint.getEndpointId())); + logger.debug("Registering endpoint with id '" + endpoint.getEndpointId() + + "' to the JMX domain"); } ObjectName objectName = this.objectNameFactory.generate(endpoint); this.mBeanServer.registerMBean(endpoint, objectName); return objectName; } catch (MalformedObjectNameException ex) { - throw new IllegalStateException( - String.format("Invalid ObjectName for " + "endpoint with id '%s'", - endpoint.getEndpointId()), - ex); + throw new IllegalStateException("Invalid ObjectName for endpoint with id '" + + endpoint.getEndpointId() + "'", ex); } catch (Exception ex) { throw new MBeanExportException( - String.format("Failed to register MBean for endpoint with id '%s'", - endpoint.getEndpointId()), + "Failed to register MBean for endpoint with id '" + + endpoint.getEndpointId() + "'", ex); } } @@ -99,8 +96,8 @@ public class EndpointMBeanRegistrar { public boolean unregisterEndpointMbean(ObjectName objectName) { try { if (logger.isDebugEnabled()) { - logger.debug(String.format("Unregister endpoint with ObjectName '%s' " - + "from the JMX domain", objectName)); + logger.debug("Unregister endpoint with ObjectName '" + objectName + "' " + + "from the JMX domain"); } this.mBeanServer.unregisterMBean(objectName); return true; @@ -110,8 +107,7 @@ public class EndpointMBeanRegistrar { } catch (MBeanRegistrationException ex) { throw new JmxException( - String.format("Failed to unregister MBean with" + "ObjectName '%s'", - objectName), + "Failed to unregister MBean with ObjectName '" + objectName + "'", ex); } } diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/JmxAnnotationEndpointDiscoverer.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/JmxAnnotationEndpointDiscoverer.java index 11b0980a83d..f56f2f3f7c9 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/JmxAnnotationEndpointDiscoverer.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/JmxAnnotationEndpointDiscoverer.java @@ -20,6 +20,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.List; import java.util.function.Function; @@ -30,11 +31,11 @@ import org.springframework.boot.endpoint.AnnotationEndpointDiscoverer; import org.springframework.boot.endpoint.CachingConfiguration; import org.springframework.boot.endpoint.CachingOperationInvoker; import org.springframework.boot.endpoint.Endpoint; +import org.springframework.boot.endpoint.EndpointDelivery; import org.springframework.boot.endpoint.EndpointInfo; -import org.springframework.boot.endpoint.EndpointOperationType; -import org.springframework.boot.endpoint.EndpointType; import org.springframework.boot.endpoint.OperationInvoker; import org.springframework.boot.endpoint.OperationParameterMapper; +import org.springframework.boot.endpoint.OperationType; import org.springframework.boot.endpoint.ReflectiveOperationInvoker; import org.springframework.context.ApplicationContext; import org.springframework.core.annotation.AnnotationAttributes; @@ -60,7 +61,6 @@ public class JmxAnnotationEndpointDiscoverer * Creates a new {@link JmxAnnotationEndpointDiscoverer} that will discover * {@link Endpoint endpoints} and {@link JmxEndpointExtension jmx extensions} using * the given {@link ApplicationContext}. - * * @param applicationContext the application context * @param parameterMapper the {@link OperationParameterMapper} used to convert * arguments when an operation is invoked @@ -75,8 +75,8 @@ public class JmxAnnotationEndpointDiscoverer @Override public Collection> discoverEndpoints() { - Collection> endpointDescriptors = discoverEndpointsWithExtension( - JmxEndpointExtension.class, EndpointType.JMX); + Collection> endpointDescriptors = discoverEndpoints( + JmxEndpointExtension.class, EndpointDelivery.JMX); verifyThatOperationsHaveDistinctName(endpointDescriptors); return endpointDescriptors.stream().map(EndpointInfoDescriptor::getEndpointInfo) .collect(Collectors.toList()); @@ -113,7 +113,7 @@ public class JmxAnnotationEndpointDiscoverer @Override public JmxEndpointOperation createOperation(String endpointId, AnnotationAttributes operationAttributes, Object target, Method method, - EndpointOperationType type, long timeToLive) { + OperationType type, long timeToLive) { String operationName = method.getName(); Class outputType = mapParameterType(method.getReturnType()); String description = getDescription(method, @@ -139,29 +139,40 @@ public class JmxAnnotationEndpointDiscoverer } private List getParameters(Method method) { - List parameters = new ArrayList<>(); Parameter[] methodParameters = method.getParameters(); if (methodParameters.length == 0) { - return parameters; + return Collections.emptyList(); } ManagedOperationParameter[] managedOperationParameters = jmxAttributeSource .getManagedOperationParameters(method); - if (managedOperationParameters.length > 0) { - for (int i = 0; i < managedOperationParameters.length; i++) { - ManagedOperationParameter mBeanParameter = managedOperationParameters[i]; - Parameter methodParameter = methodParameters[i]; - parameters.add(new JmxEndpointOperationParameterInfo( - mBeanParameter.getName(), - mapParameterType(methodParameter.getType()), - mBeanParameter.getDescription())); - } + if (managedOperationParameters.length == 0) { + return getParametersInfo(methodParameters); } - else { - for (Parameter parameter : methodParameters) { - parameters.add( - new JmxEndpointOperationParameterInfo(parameter.getName(), - mapParameterType(parameter.getType()), null)); - } + return getParametersInfo(methodParameters, managedOperationParameters); + } + + private List getParametersInfo( + Parameter[] methodParameters) { + List parameters = new ArrayList<>(); + for (Parameter methodParameter : methodParameters) { + String name = methodParameter.getName(); + Class type = mapParameterType(methodParameter.getType()); + parameters.add(new JmxEndpointOperationParameterInfo(name, type, null)); + } + return parameters; + } + + private List getParametersInfo( + Parameter[] methodParameters, + ManagedOperationParameter[] managedOperationParameters) { + List parameters = new ArrayList<>(); + for (int i = 0; i < managedOperationParameters.length; i++) { + ManagedOperationParameter managedOperationParameter = managedOperationParameters[i]; + Parameter methodParameter = methodParameters[i]; + parameters.add(new JmxEndpointOperationParameterInfo( + managedOperationParameter.getName(), + mapParameterType(methodParameter.getType()), + managedOperationParameter.getDescription())); } return parameters; } diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/JmxEndpointMBeanFactory.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/JmxEndpointMBeanFactory.java index abfa353a7c8..18c10e354ec 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/JmxEndpointMBeanFactory.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/JmxEndpointMBeanFactory.java @@ -51,11 +51,13 @@ public class JmxEndpointMBeanFactory { */ public Collection createMBeans( Collection> endpoints) { - return endpoints.stream().map((endpointInfo) -> { - EndpointMBeanInfo endpointMBeanInfo = this.assembler - .createEndpointMBeanInfo(endpointInfo); - return new EndpointMBean(this.resultMapper::mapResponse, endpointMBeanInfo); - }).collect(Collectors.toList()); + return endpoints.stream().map(this::createMBean).collect(Collectors.toList()); + } + + private EndpointMBean createMBean(EndpointInfo endpointInfo) { + EndpointMBeanInfo endpointMBeanInfo = this.assembler + .createEndpointMBeanInfo(endpointInfo); + return new EndpointMBean(this.resultMapper::mapResponse, endpointMBeanInfo); } } diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/JmxEndpointOperation.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/JmxEndpointOperation.java index e8dc4f51883..5dca8e9d4bb 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/JmxEndpointOperation.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/jmx/JmxEndpointOperation.java @@ -19,9 +19,9 @@ package org.springframework.boot.endpoint.jmx; import java.util.Collections; import java.util.List; -import org.springframework.boot.endpoint.EndpointOperation; -import org.springframework.boot.endpoint.EndpointOperationType; +import org.springframework.boot.endpoint.Operation; import org.springframework.boot.endpoint.OperationInvoker; +import org.springframework.boot.endpoint.OperationType; /** * An operation on a JMX endpoint. @@ -30,7 +30,7 @@ import org.springframework.boot.endpoint.OperationInvoker; * @author Andy Wilkinson * @since 2.0.0 */ -public class JmxEndpointOperation extends EndpointOperation { +public class JmxEndpointOperation extends Operation { private final String operationName; @@ -50,7 +50,7 @@ public class JmxEndpointOperation extends EndpointOperation { * @param description the description of the operation * @param parameters the parameters of the operation */ - public JmxEndpointOperation(EndpointOperationType type, OperationInvoker invoker, + public JmxEndpointOperation(OperationType type, OperationInvoker invoker, String operationName, Class outputType, String description, List parameters) { super(type, invoker, true); diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/web/EndpointLinksResolver.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/web/EndpointLinksResolver.java index 647a59c69fd..fdc246b6769 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/web/EndpointLinksResolver.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/web/EndpointLinksResolver.java @@ -33,7 +33,6 @@ public class EndpointLinksResolver { /** * Resolves links to the operations of the given {code webEndpoints} based on a * request with the given {@code requestUrl}. - * * @param webEndpoints the web endpoints * @param requestUrl the url of the request for the endpoint links * @return the links diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/web/OperationRequestPredicate.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/web/OperationRequestPredicate.java index 805e23a5cd4..ac713efe770 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/web/OperationRequestPredicate.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/web/OperationRequestPredicate.java @@ -111,26 +111,16 @@ public class OperationRequestPredicate { if (this == obj) { return true; } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { + if (obj == null || getClass() != obj.getClass()) { return false; } OperationRequestPredicate other = (OperationRequestPredicate) obj; - if (!this.consumes.equals(other.consumes)) { - return false; - } - if (this.httpMethod != other.httpMethod) { - return false; - } - if (!this.canonicalPath.equals(other.canonicalPath)) { - return false; - } - if (!this.produces.equals(other.produces)) { - return false; - } - return true; + boolean result = true; + result = result && this.consumes.equals(other.consumes); + result = result && this.httpMethod == other.httpMethod; + result = result && this.canonicalPath.equals(other.canonicalPath); + result = result && this.produces.equals(other.produces); + return result; } } diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/web/WebAnnotationEndpointDiscoverer.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/web/WebAnnotationEndpointDiscoverer.java index 35390beb12d..85ce0017c77 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/web/WebAnnotationEndpointDiscoverer.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/web/WebAnnotationEndpointDiscoverer.java @@ -31,11 +31,11 @@ import org.springframework.boot.endpoint.AnnotationEndpointDiscoverer; import org.springframework.boot.endpoint.CachingConfiguration; import org.springframework.boot.endpoint.CachingOperationInvoker; import org.springframework.boot.endpoint.Endpoint; +import org.springframework.boot.endpoint.EndpointDelivery; import org.springframework.boot.endpoint.EndpointInfo; -import org.springframework.boot.endpoint.EndpointOperationType; -import org.springframework.boot.endpoint.EndpointType; import org.springframework.boot.endpoint.OperationInvoker; import org.springframework.boot.endpoint.OperationParameterMapper; +import org.springframework.boot.endpoint.OperationType; import org.springframework.boot.endpoint.ReflectiveOperationInvoker; import org.springframework.boot.endpoint.Selector; import org.springframework.context.ApplicationContext; @@ -79,8 +79,8 @@ public class WebAnnotationEndpointDiscoverer extends @Override public Collection> discoverEndpoints() { - Collection> endpoints = discoverEndpointsWithExtension( - WebEndpointExtension.class, EndpointType.WEB); + Collection> endpoints = discoverEndpoints( + WebEndpointExtension.class, EndpointDelivery.WEB); verifyThatOperationsHaveDistinctPredicates(endpoints); return endpoints.stream().map(EndpointInfoDescriptor::getEndpointInfo) .collect(Collectors.toList()); @@ -129,7 +129,7 @@ public class WebAnnotationEndpointDiscoverer extends @Override public WebEndpointOperation createOperation(String endpointId, AnnotationAttributes operationAttributes, Object target, Method method, - EndpointOperationType type, long timeToLive) { + OperationType type, long timeToLive) { WebEndpointHttpMethod httpMethod = determineHttpMethod(type); OperationRequestPredicate requestPredicate = new OperationRequestPredicate( determinePath(endpointId, method), httpMethod, @@ -201,9 +201,8 @@ public class WebAnnotationEndpointDiscoverer extends (parameter) -> parameter.getAnnotation(Selector.class) == null); } - private WebEndpointHttpMethod determineHttpMethod( - EndpointOperationType operationType) { - if (operationType == EndpointOperationType.WRITE) { + private WebEndpointHttpMethod determineHttpMethod(OperationType operationType) { + if (operationType == OperationType.WRITE) { return WebEndpointHttpMethod.POST; } return WebEndpointHttpMethod.GET; diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/web/WebEndpointOperation.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/web/WebEndpointOperation.java index df87213729c..28e0bfd181e 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/web/WebEndpointOperation.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/web/WebEndpointOperation.java @@ -16,9 +16,9 @@ package org.springframework.boot.endpoint.web; -import org.springframework.boot.endpoint.EndpointOperation; -import org.springframework.boot.endpoint.EndpointOperationType; +import org.springframework.boot.endpoint.Operation; import org.springframework.boot.endpoint.OperationInvoker; +import org.springframework.boot.endpoint.OperationType; /** * An operation on a web endpoint. @@ -26,7 +26,7 @@ import org.springframework.boot.endpoint.OperationInvoker; * @author Andy Wilkinson * @since 2.0.0 */ -public class WebEndpointOperation extends EndpointOperation { +public class WebEndpointOperation extends Operation { private final OperationRequestPredicate requestPredicate; @@ -42,9 +42,8 @@ public class WebEndpointOperation extends EndpointOperation { * @param requestPredicate the predicate for requests that can be handled by the * @param id the id of the operation, unique within its endpoint operation */ - public WebEndpointOperation(EndpointOperationType type, - OperationInvoker operationInvoker, boolean blocking, - OperationRequestPredicate requestPredicate, String id) { + public WebEndpointOperation(OperationType type, OperationInvoker operationInvoker, + boolean blocking, OperationRequestPredicate requestPredicate, String id) { super(type, operationInvoker, blocking); this.requestPredicate = requestPredicate; this.id = id; diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/web/jersey/JerseyEndpointResourceFactory.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/web/jersey/JerseyEndpointResourceFactory.java index e79bd587732..69f0f80b027 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/web/jersey/JerseyEndpointResourceFactory.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/web/jersey/JerseyEndpointResourceFactory.java @@ -80,7 +80,7 @@ public class JerseyEndpointResourceFactory { resourceBuilder.addMethod(requestPredicate.getHttpMethod().name()) .consumes(toStringArray(requestPredicate.getConsumes())) .produces(toStringArray(requestPredicate.getProduces())) - .handledBy(new EndpointInvokingInflector(operation.getOperationInvoker(), + .handledBy(new EndpointInvokingInflector(operation.getInvoker(), !requestPredicate.getConsumes().isEmpty())); return resourceBuilder.build(); } @@ -110,28 +110,32 @@ public class JerseyEndpointResourceFactory { this.readBody = readBody; } - @SuppressWarnings("unchecked") @Override public Response apply(ContainerRequestContext data) { Map arguments = new HashMap<>(); if (this.readBody) { - Map body = ((ContainerRequest) data) - .readEntity(Map.class); - if (body != null) { - arguments.putAll(body); - } + arguments.putAll(extractBodyArguments(data)); } arguments.putAll(extractPathParameters(data)); arguments.putAll(extractQueryParameters(data)); try { - return convertToJaxRsResponse(this.operationInvoker.invoke(arguments), - data.getRequest().getMethod()); + Object response = this.operationInvoker.invoke(arguments); + return convertToJaxRsResponse(response, data.getRequest().getMethod()); } catch (ParameterMappingException ex) { return Response.status(Status.BAD_REQUEST).build(); } } + @SuppressWarnings("unchecked") + private Map extractBodyArguments(ContainerRequestContext data) { + Map entity = ((ContainerRequest) data).readEntity(Map.class); + if (entity == null) { + return Collections.emptyMap(); + } + return (Map) entity; + } + private Map extractPathParameters( ContainerRequestContext requestContext) { return extract(requestContext.getUriInfo().getPathParameters()); @@ -155,8 +159,9 @@ public class JerseyEndpointResourceFactory { private Response convertToJaxRsResponse(Object response, String httpMethod) { if (response == null) { - return Response.status(HttpMethod.GET.equals(httpMethod) - ? Status.NOT_FOUND : Status.NO_CONTENT).build(); + boolean isGet = HttpMethod.GET.equals(httpMethod); + Status status = (isGet ? Status.NOT_FOUND : Status.NO_CONTENT); + return Response.status(status).build(); } try { if (!(response instanceof WebEndpointResponse)) { diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/web/mvc/AbstractWebEndpointServletHandlerMapping.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/web/mvc/AbstractWebEndpointServletHandlerMapping.java index 22b53e92ee8..f07430e459d 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/web/mvc/AbstractWebEndpointServletHandlerMapping.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/web/mvc/AbstractWebEndpointServletHandlerMapping.java @@ -47,8 +47,8 @@ import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMappi * @author Madhura Bhave * @since 2.0.0 */ -public abstract class AbstractWebEndpointServletHandlerMapping extends RequestMappingInfoHandlerMapping - implements InitializingBean { +public abstract class AbstractWebEndpointServletHandlerMapping + extends RequestMappingInfoHandlerMapping implements InitializingBean { private final String endpointPath; @@ -96,9 +96,12 @@ public abstract class AbstractWebEndpointServletHandlerMapping extends RequestMa this.webEndpoints.stream() .flatMap((webEndpoint) -> webEndpoint.getOperations().stream()) .forEach(this::registerMappingForOperation); - registerMapping(new RequestMappingInfo(patternsRequestConditionForPattern(""), - new RequestMethodsRequestCondition(RequestMethod.GET), null, null, null, - null, null), this, getLinks()); + PatternsRequestCondition patterns = patternsRequestConditionForPattern(""); + RequestMethodsRequestCondition methods = new RequestMethodsRequestCondition( + RequestMethod.GET); + RequestMappingInfo mapping = new RequestMappingInfo(patterns, methods, null, null, + null, null, null); + registerMapping(mapping, this, getLinks()); } @Override @@ -114,23 +117,22 @@ public abstract class AbstractWebEndpointServletHandlerMapping extends RequestMa protected RequestMappingInfo createRequestMappingInfo( WebEndpointOperation operationInfo) { OperationRequestPredicate requestPredicate = operationInfo.getRequestPredicate(); - return new RequestMappingInfo(null, - patternsRequestConditionForPattern(requestPredicate.getPath()), - new RequestMethodsRequestCondition( - RequestMethod.valueOf(requestPredicate.getHttpMethod().name())), - null, null, - new ConsumesRequestCondition( - toStringArray(requestPredicate.getConsumes())), - new ProducesRequestCondition( - toStringArray(requestPredicate.getProduces())), - null); + PatternsRequestCondition patterns = patternsRequestConditionForPattern( + requestPredicate.getPath()); + RequestMethodsRequestCondition methods = new RequestMethodsRequestCondition( + RequestMethod.valueOf(requestPredicate.getHttpMethod().name())); + ConsumesRequestCondition consumes = new ConsumesRequestCondition( + toStringArray(requestPredicate.getConsumes())); + ProducesRequestCondition produces = new ProducesRequestCondition( + toStringArray(requestPredicate.getProduces())); + return new RequestMappingInfo(null, patterns, methods, null, null, consumes, + produces, null); } private PatternsRequestCondition patternsRequestConditionForPattern(String path) { - return new PatternsRequestCondition( - new String[] { this.endpointPath - + (StringUtils.hasText(path) ? "/" + path : "") }, - null, null, false, false); + String[] patterns = new String[] { + this.endpointPath + (StringUtils.hasText(path) ? "/" + path : "") }; + return new PatternsRequestCondition(patterns, null, null, false, false); } private String[] toStringArray(Collection collection) { @@ -172,5 +174,4 @@ public abstract class AbstractWebEndpointServletHandlerMapping extends RequestMa } - } diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/web/mvc/WebEndpointServletHandlerMapping.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/web/mvc/WebEndpointServletHandlerMapping.java index 51195333446..0797da651ad 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/web/mvc/WebEndpointServletHandlerMapping.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/web/mvc/WebEndpointServletHandlerMapping.java @@ -49,7 +49,8 @@ import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMappi * @author Andy Wilkinson * @since 2.0.0 */ -public class WebEndpointServletHandlerMapping extends AbstractWebEndpointServletHandlerMapping { +public class WebEndpointServletHandlerMapping + extends AbstractWebEndpointServletHandlerMapping { private final Method handle = ReflectionUtils.findMethod(OperationHandler.class, "handle", HttpServletRequest.class, Map.class); @@ -84,11 +85,13 @@ public class WebEndpointServletHandlerMapping extends AbstractWebEndpointServlet setOrder(-100); } + @Override protected void registerMappingForOperation(WebEndpointOperation operation) { registerMapping(createRequestMappingInfo(operation), - new OperationHandler(operation.getOperationInvoker()), this.handle); + new OperationHandler(operation.getInvoker()), this.handle); } + @Override protected Method getLinks() { return this.links; } diff --git a/spring-boot/src/main/java/org/springframework/boot/endpoint/web/reactive/WebEndpointReactiveHandlerMapping.java b/spring-boot/src/main/java/org/springframework/boot/endpoint/web/reactive/WebEndpointReactiveHandlerMapping.java index 890746cb1be..300df992804 100644 --- a/spring-boot/src/main/java/org/springframework/boot/endpoint/web/reactive/WebEndpointReactiveHandlerMapping.java +++ b/spring-boot/src/main/java/org/springframework/boot/endpoint/web/reactive/WebEndpointReactiveHandlerMapping.java @@ -24,8 +24,8 @@ import java.util.Map; import org.springframework.beans.factory.InitializingBean; import org.springframework.boot.endpoint.EndpointInfo; -import org.springframework.boot.endpoint.EndpointOperationType; import org.springframework.boot.endpoint.OperationInvoker; +import org.springframework.boot.endpoint.OperationType; import org.springframework.boot.endpoint.ParameterMappingException; import org.springframework.boot.endpoint.web.EndpointLinksResolver; import org.springframework.boot.endpoint.web.Link; @@ -126,29 +126,28 @@ public class WebEndpointReactiveHandlerMapping extends RequestMappingInfoHandler } private void registerMappingForOperation(WebEndpointOperation operation) { - EndpointOperationType operationType = operation.getType(); + OperationType operationType = operation.getType(); registerMapping(createRequestMappingInfo(operation), - operationType == EndpointOperationType.WRITE - ? new WriteOperationHandler(operation.getOperationInvoker()) - : new ReadOperationHandler(operation.getOperationInvoker()), - operationType == EndpointOperationType.WRITE ? this.handleWrite + operationType == OperationType.WRITE + ? new WriteOperationHandler(operation.getInvoker()) + : new ReadOperationHandler(operation.getInvoker()), + operationType == OperationType.WRITE ? this.handleWrite : this.handleRead); } private RequestMappingInfo createRequestMappingInfo( WebEndpointOperation operationInfo) { OperationRequestPredicate requestPredicate = operationInfo.getRequestPredicate(); - return new RequestMappingInfo(null, - new PatternsRequestCondition(pathPatternParser - .parse(this.endpointPath + "/" + requestPredicate.getPath())), - new RequestMethodsRequestCondition( - RequestMethod.valueOf(requestPredicate.getHttpMethod().name())), - null, null, - new ConsumesRequestCondition( - toStringArray(requestPredicate.getConsumes())), - new ProducesRequestCondition( - toStringArray(requestPredicate.getProduces())), - null); + PatternsRequestCondition patterns = new PatternsRequestCondition(pathPatternParser + .parse(this.endpointPath + "/" + requestPredicate.getPath())); + RequestMethodsRequestCondition methods = new RequestMethodsRequestCondition( + RequestMethod.valueOf(requestPredicate.getHttpMethod().name())); + ConsumesRequestCondition consumes = new ConsumesRequestCondition( + toStringArray(requestPredicate.getConsumes())); + ProducesRequestCondition produces = new ProducesRequestCondition( + toStringArray(requestPredicate.getProduces())); + return new RequestMappingInfo(null, patterns, methods, null, null, consumes, + produces, null); } private String[] toStringArray(Collection collection) { diff --git a/spring-boot/src/test/java/org/springframework/boot/endpoint/AnnotationEndpointDiscovererTests.java b/spring-boot/src/test/java/org/springframework/boot/endpoint/AnnotationEndpointDiscovererTests.java index 0b680354fbd..e7713f6fc7a 100644 --- a/spring-boot/src/test/java/org/springframework/boot/endpoint/AnnotationEndpointDiscovererTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/endpoint/AnnotationEndpointDiscovererTests.java @@ -116,7 +116,7 @@ public class AnnotationEndpointDiscovererTests { endpoints.get("test")); assertThat(operations).hasSize(3); operations.values() - .forEach(operation -> assertThat(operation.getOperationInvoker()) + .forEach(operation -> assertThat(operation.getInvoker()) .isNotInstanceOf(CachingOperationInvoker.class)); }); } @@ -135,7 +135,7 @@ public class AnnotationEndpointDiscovererTests { endpoints.get("test")); assertThat(operations).hasSize(3); operations.values() - .forEach(operation -> assertThat(operation.getOperationInvoker()) + .forEach(operation -> assertThat(operation.getInvoker()) .isNotInstanceOf(CachingOperationInvoker.class)); }); } @@ -154,16 +154,16 @@ public class AnnotationEndpointDiscovererTests { endpoints.get("test")); OperationInvoker getAllOperationInvoker = operations .get(ReflectionUtils.findMethod(TestEndpoint.class, "getAll")) - .getOperationInvoker(); + .getInvoker(); assertThat(getAllOperationInvoker) .isInstanceOf(CachingOperationInvoker.class); assertThat(((CachingOperationInvoker) getAllOperationInvoker).getTimeToLive()) .isEqualTo(500); assertThat(operations.get(ReflectionUtils.findMethod(TestEndpoint.class, - "getOne", String.class)).getOperationInvoker()) + "getOne", String.class)).getInvoker()) .isNotInstanceOf(CachingOperationInvoker.class); assertThat(operations.get(ReflectionUtils.findMethod(TestEndpoint.class, - "update", String.class, String.class)).getOperationInvoker()) + "update", String.class, String.class)).getInvoker()) .isNotInstanceOf(CachingOperationInvoker.class); }); } @@ -186,7 +186,7 @@ public class AnnotationEndpointDiscovererTests { EndpointInfo endpoint) { Map operationByMethod = new HashMap<>(); endpoint.getOperations().forEach((operation) -> { - EndpointOperation existing = operationByMethod + Operation existing = operationByMethod .put(operation.getOperationMethod(), operation); if (existing != null) { throw new AssertionError(String.format( @@ -281,11 +281,11 @@ public class AnnotationEndpointDiscovererTests { } } - private static final class TestEndpointOperation extends EndpointOperation { + private static final class TestEndpointOperation extends Operation { private final Method operationMethod; - private TestEndpointOperation(EndpointOperationType type, + private TestEndpointOperation(OperationType type, OperationInvoker operationInvoker, Method operationMethod) { super(type, operationInvoker, true); this.operationMethod = operationMethod; @@ -313,7 +313,7 @@ public class AnnotationEndpointDiscovererTests { @Override public Collection> discoverEndpoints() { - return discoverEndpointsWithExtension(null, null).stream() + return discoverEndpoints(null, null).stream() .map(EndpointInfoDescriptor::getEndpointInfo) .collect(Collectors.toList()); } @@ -324,7 +324,7 @@ public class AnnotationEndpointDiscovererTests { @Override public TestEndpointOperation createOperation(String endpointId, AnnotationAttributes operationAttributes, Object target, - Method operationMethod, EndpointOperationType operationType, + Method operationMethod, OperationType operationType, long timeToLive) { return new TestEndpointOperation(operationType, createOperationInvoker(timeToLive), operationMethod); diff --git a/spring-boot/src/test/java/org/springframework/boot/endpoint/jmx/EndpointMBeanInfoAssemblerTests.java b/spring-boot/src/test/java/org/springframework/boot/endpoint/jmx/EndpointMBeanInfoAssemblerTests.java index 34fc5caacb0..acdde394ac6 100644 --- a/spring-boot/src/test/java/org/springframework/boot/endpoint/jmx/EndpointMBeanInfoAssemblerTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/endpoint/jmx/EndpointMBeanInfoAssemblerTests.java @@ -26,8 +26,8 @@ import javax.management.MBeanParameterInfo; import org.junit.Test; import org.springframework.boot.endpoint.EndpointInfo; -import org.springframework.boot.endpoint.EndpointOperationType; import org.springframework.boot.endpoint.OperationInvoker; +import org.springframework.boot.endpoint.OperationType; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; @@ -44,9 +44,9 @@ public class EndpointMBeanInfoAssemblerTests { @Test public void exposeSimpleReadOperation() { - JmxEndpointOperation operation = new JmxEndpointOperation( - EndpointOperationType.READ, new DummyOperationInvoker(), "getAll", - Object.class, "Test operation", Collections.emptyList()); + JmxEndpointOperation operation = new JmxEndpointOperation(OperationType.READ, + new DummyOperationInvoker(), "getAll", Object.class, "Test operation", + Collections.emptyList()); EndpointInfo endpoint = new EndpointInfo<>("test", true, Collections.singletonList(operation)); EndpointMBeanInfo endpointMBeanInfo = this.mBeanInfoAssembler @@ -73,9 +73,8 @@ public class EndpointMBeanInfoAssemblerTests { @Test public void exposeSimpleWriteOperation() { - JmxEndpointOperation operation = new JmxEndpointOperation( - EndpointOperationType.WRITE, new DummyOperationInvoker(), "update", - Object.class, "Update operation", + JmxEndpointOperation operation = new JmxEndpointOperation(OperationType.WRITE, + new DummyOperationInvoker(), "update", Object.class, "Update operation", Collections.singletonList(new JmxEndpointOperationParameterInfo("test", String.class, "Test argument"))); EndpointInfo endpoint = new EndpointInfo<>("another", true, diff --git a/spring-boot/src/test/java/org/springframework/boot/endpoint/jmx/JmxAnnotationEndpointDiscovererTests.java b/spring-boot/src/test/java/org/springframework/boot/endpoint/jmx/JmxAnnotationEndpointDiscovererTests.java index 0090ac27e28..0a8073abc23 100644 --- a/spring-boot/src/test/java/org/springframework/boot/endpoint/jmx/JmxAnnotationEndpointDiscovererTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/endpoint/jmx/JmxAnnotationEndpointDiscovererTests.java @@ -31,8 +31,8 @@ import org.springframework.boot.endpoint.CachingConfiguration; import org.springframework.boot.endpoint.CachingOperationInvoker; import org.springframework.boot.endpoint.ConversionServiceOperationParameterMapper; import org.springframework.boot.endpoint.Endpoint; +import org.springframework.boot.endpoint.EndpointDelivery; import org.springframework.boot.endpoint.EndpointInfo; -import org.springframework.boot.endpoint.EndpointType; import org.springframework.boot.endpoint.ReadOperation; import org.springframework.boot.endpoint.ReflectiveOperationInvoker; import org.springframework.boot.endpoint.WriteOperation; @@ -77,7 +77,7 @@ public class JmxAnnotationEndpointDiscovererTests { .isEqualTo("Invoke getAll for endpoint test"); assertThat(getAll.getOutputType()).isEqualTo(Object.class); assertThat(getAll.getParameters()).isEmpty(); - assertThat(getAll.getOperationInvoker()) + assertThat(getAll.getInvoker()) .isInstanceOf(ReflectiveOperationInvoker.class); JmxEndpointOperation getSomething = operationByName.get("getSomething"); assertThat(getSomething.getDescription()) @@ -155,10 +155,9 @@ public class JmxAnnotationEndpointDiscovererTests { assertThat(operationByName).containsOnlyKeys("getAll", "getSomething", "update"); JmxEndpointOperation getAll = operationByName.get("getAll"); - assertThat(getAll.getOperationInvoker()) - .isInstanceOf(CachingOperationInvoker.class); - assertThat(((CachingOperationInvoker) getAll.getOperationInvoker()) - .getTimeToLive()).isEqualTo(500); + assertThat(getAll.getInvoker()).isInstanceOf(CachingOperationInvoker.class); + assertThat(((CachingOperationInvoker) getAll.getInvoker()).getTimeToLive()) + .isEqualTo(500); }); } @@ -174,16 +173,15 @@ public class JmxAnnotationEndpointDiscovererTests { assertThat(operationByName).containsOnlyKeys("getAll", "getSomething", "update", "getAnother"); JmxEndpointOperation getAll = operationByName.get("getAll"); - assertThat(getAll.getOperationInvoker()) + assertThat(getAll.getInvoker()) .isInstanceOf(CachingOperationInvoker.class); - assertThat(((CachingOperationInvoker) getAll.getOperationInvoker()) + assertThat(((CachingOperationInvoker) getAll.getInvoker()) .getTimeToLive()).isEqualTo(500); JmxEndpointOperation getAnother = operationByName.get("getAnother"); - assertThat(getAnother.getOperationInvoker()) + assertThat(getAnother.getInvoker()) .isInstanceOf(CachingOperationInvoker.class); - assertThat( - ((CachingOperationInvoker) getAnother.getOperationInvoker()) - .getTimeToLive()).isEqualTo(500); + assertThat(((CachingOperationInvoker) getAnother.getInvoker()) + .getTimeToLive()).isEqualTo(500); }); } @@ -333,7 +331,7 @@ public class JmxAnnotationEndpointDiscovererTests { } - @Endpoint(id = "jmx", types = EndpointType.JMX) + @Endpoint(id = "jmx", delivery = EndpointDelivery.JMX) private static class TestJmxEndpoint { @ReadOperation @@ -412,7 +410,7 @@ public class JmxAnnotationEndpointDiscovererTests { } - @Endpoint(id = "nonjmx", types = EndpointType.WEB) + @Endpoint(id = "nonjmx", delivery = EndpointDelivery.WEB) private static class NonJmxEndpoint { @ReadOperation diff --git a/spring-boot/src/test/java/org/springframework/boot/endpoint/web/EndpointLinksResolverTests.java b/spring-boot/src/test/java/org/springframework/boot/endpoint/web/EndpointLinksResolverTests.java index efd3f6bb10a..568011cc758 100644 --- a/spring-boot/src/test/java/org/springframework/boot/endpoint/web/EndpointLinksResolverTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/endpoint/web/EndpointLinksResolverTests.java @@ -24,7 +24,7 @@ import org.assertj.core.api.Condition; import org.junit.Test; import org.springframework.boot.endpoint.EndpointInfo; -import org.springframework.boot.endpoint.EndpointOperationType; +import org.springframework.boot.endpoint.OperationType; import static org.assertj.core.api.Assertions.assertThat; @@ -74,7 +74,7 @@ public class EndpointLinksResolverTests { } private WebEndpointOperation operationWithPath(String path, String id) { - return new WebEndpointOperation(EndpointOperationType.READ, null, false, + return new WebEndpointOperation(OperationType.READ, null, false, new OperationRequestPredicate(path, WebEndpointHttpMethod.GET, Collections.emptyList(), Collections.emptyList()), id); diff --git a/spring-boot/src/test/java/org/springframework/boot/endpoint/web/WebAnnotationEndpointDiscovererTests.java b/spring-boot/src/test/java/org/springframework/boot/endpoint/web/WebAnnotationEndpointDiscovererTests.java index 2af16b2be74..cad8296c020 100644 --- a/spring-boot/src/test/java/org/springframework/boot/endpoint/web/WebAnnotationEndpointDiscovererTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/endpoint/web/WebAnnotationEndpointDiscovererTests.java @@ -37,8 +37,8 @@ import org.springframework.boot.endpoint.CachingConfiguration; import org.springframework.boot.endpoint.CachingOperationInvoker; import org.springframework.boot.endpoint.ConversionServiceOperationParameterMapper; import org.springframework.boot.endpoint.Endpoint; +import org.springframework.boot.endpoint.EndpointDelivery; import org.springframework.boot.endpoint.EndpointInfo; -import org.springframework.boot.endpoint.EndpointType; import org.springframework.boot.endpoint.OperationInvoker; import org.springframework.boot.endpoint.ReadOperation; import org.springframework.boot.endpoint.Selector; @@ -194,7 +194,7 @@ public class WebAnnotationEndpointDiscovererTests { EndpointInfo endpoint = endpoints.get("test"); assertThat(endpoint.getOperations()).hasSize(1); OperationInvoker operationInvoker = endpoint.getOperations() - .iterator().next().getOperationInvoker(); + .iterator().next().getInvoker(); assertThat(operationInvoker) .isInstanceOf(CachingOperationInvoker.class); assertThat( @@ -375,7 +375,7 @@ public class WebAnnotationEndpointDiscovererTests { } - @Endpoint(id = "nonweb", types = EndpointType.JMX) + @Endpoint(id = "nonweb", delivery = EndpointDelivery.JMX) static class NonWebEndpoint { @ReadOperation