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