Commit 138d8547 authored by Phillip Webb's avatar Phillip Webb

Support mixed case endpoint IDs with time-to-live

Update the endpoint time-to-live binding logic so that mixed case
endpoint IDs are supported. Prior to this commit an
`InvalidConfigurationPropertyNameException` would be thrown when using
a camel case endpoint ID.

See gh-14773
parent 3105a388
...@@ -19,6 +19,7 @@ package org.springframework.boot.actuate.autoconfigure.endpoint; ...@@ -19,6 +19,7 @@ package org.springframework.boot.actuate.autoconfigure.endpoint;
import java.time.Duration; import java.time.Duration;
import java.util.function.Function; import java.util.function.Function;
import org.springframework.boot.actuate.endpoint.EndpointId;
import org.springframework.boot.actuate.endpoint.invoker.cache.CachingOperationInvokerAdvisor; import org.springframework.boot.actuate.endpoint.invoker.cache.CachingOperationInvokerAdvisor;
import org.springframework.boot.context.properties.bind.BindResult; import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Bindable;
...@@ -33,7 +34,7 @@ import org.springframework.core.env.PropertyResolver; ...@@ -33,7 +34,7 @@ import org.springframework.core.env.PropertyResolver;
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Phillip Webb * @author Phillip Webb
*/ */
class EndpointIdTimeToLivePropertyFunction implements Function<String, Long> { class EndpointIdTimeToLivePropertyFunction implements Function<EndpointId, Long> {
private static final Bindable<Duration> DURATION = Bindable.of(Duration.class); private static final Bindable<Duration> DURATION = Bindable.of(Duration.class);
...@@ -48,9 +49,9 @@ class EndpointIdTimeToLivePropertyFunction implements Function<String, Long> { ...@@ -48,9 +49,9 @@ class EndpointIdTimeToLivePropertyFunction implements Function<String, Long> {
} }
@Override @Override
public Long apply(String endpointId) { public Long apply(EndpointId endpointId) {
String name = String.format("management.endpoint.%s.cache.time-to-live", String name = String.format("management.endpoint.%s.cache.time-to-live",
endpointId); endpointId.toLowerCaseString());
BindResult<Duration> duration = Binder.get(this.environment).bind(name, DURATION); BindResult<Duration> duration = Binder.get(this.environment).bind(name, DURATION);
return duration.map(Duration::toMillis).orElse(null); return duration.map(Duration::toMillis).orElse(null);
} }
......
...@@ -73,8 +73,8 @@ public class CloudFoundryWebEndpointDiscovererTests { ...@@ -73,8 +73,8 @@ public class CloudFoundryWebEndpointDiscovererTests {
this.load((id) -> null, (id) -> id, configuration, consumer); this.load((id) -> null, (id) -> id, configuration, consumer);
} }
private void load(Function<String, Long> timeToLive, PathMapper endpointPathMapper, private void load(Function<EndpointId, Long> timeToLive,
Class<?> configuration, PathMapper endpointPathMapper, Class<?> configuration,
Consumer<CloudFoundryWebEndpointDiscoverer> consumer) { Consumer<CloudFoundryWebEndpointDiscoverer> consumer) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
configuration); configuration);
......
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -20,6 +20,7 @@ import java.util.function.Function; ...@@ -20,6 +20,7 @@ import java.util.function.Function;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.actuate.endpoint.EndpointId;
import org.springframework.mock.env.MockEnvironment; import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
...@@ -34,21 +35,26 @@ public class EndpointIdTimeToLivePropertyFunctionTests { ...@@ -34,21 +35,26 @@ public class EndpointIdTimeToLivePropertyFunctionTests {
private final MockEnvironment environment = new MockEnvironment(); private final MockEnvironment environment = new MockEnvironment();
private final Function<String, Long> timeToLive = new EndpointIdTimeToLivePropertyFunction( private final Function<EndpointId, Long> timeToLive = new EndpointIdTimeToLivePropertyFunction(
this.environment); this.environment);
@Test @Test
public void defaultConfiguration() { public void defaultConfiguration() {
Long result = this.timeToLive.apply("test"); Long result = this.timeToLive.apply(EndpointId.of("test"));
assertThat(result).isNull(); assertThat(result).isNull();
} }
@Test @Test
public void userConfiguration() { public void userConfiguration() {
this.environment.setProperty("management.endpoint.test.cache.time-to-live", this.environment.setProperty(
"500"); "management.endpoint.another-test.cache.time-to-live", "500");
Long result = this.timeToLive.apply("test"); Long result = this.timeToLive.apply(EndpointId.of("anotherTest"));
assertThat(result).isEqualTo(500L); assertThat(result).isEqualTo(500L);
} }
@Test
public void mixedCaseUserConfiguration() {
}
} }
...@@ -18,6 +18,7 @@ package org.springframework.boot.actuate.endpoint.invoker.cache; ...@@ -18,6 +18,7 @@ package org.springframework.boot.actuate.endpoint.invoker.cache;
import java.util.function.Function; import java.util.function.Function;
import org.springframework.boot.actuate.endpoint.EndpointId;
import org.springframework.boot.actuate.endpoint.OperationType; import org.springframework.boot.actuate.endpoint.OperationType;
import org.springframework.boot.actuate.endpoint.SecurityContext; import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker; import org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;
...@@ -33,9 +34,10 @@ import org.springframework.boot.actuate.endpoint.invoke.OperationParameters; ...@@ -33,9 +34,10 @@ import org.springframework.boot.actuate.endpoint.invoke.OperationParameters;
*/ */
public class CachingOperationInvokerAdvisor implements OperationInvokerAdvisor { public class CachingOperationInvokerAdvisor implements OperationInvokerAdvisor {
private final Function<String, Long> endpointIdTimeToLive; private final Function<EndpointId, Long> endpointIdTimeToLive;
public CachingOperationInvokerAdvisor(Function<String, Long> endpointIdTimeToLive) { public CachingOperationInvokerAdvisor(
Function<EndpointId, Long> endpointIdTimeToLive) {
this.endpointIdTimeToLive = endpointIdTimeToLive; this.endpointIdTimeToLive = endpointIdTimeToLive;
} }
...@@ -43,6 +45,12 @@ public class CachingOperationInvokerAdvisor implements OperationInvokerAdvisor { ...@@ -43,6 +45,12 @@ public class CachingOperationInvokerAdvisor implements OperationInvokerAdvisor {
@Deprecated @Deprecated
public OperationInvoker apply(String endpointId, OperationType operationType, public OperationInvoker apply(String endpointId, OperationType operationType,
OperationParameters parameters, OperationInvoker invoker) { OperationParameters parameters, OperationInvoker invoker) {
return apply(EndpointId.of(endpointId), operationType, parameters, invoker);
}
@Override
public OperationInvoker apply(EndpointId endpointId, OperationType operationType,
OperationParameters parameters, OperationInvoker invoker) {
if (operationType == OperationType.READ && !hasMandatoryParameter(parameters)) { if (operationType == OperationType.READ && !hasMandatoryParameter(parameters)) {
Long timeToLive = this.endpointIdTimeToLive.apply(endpointId); Long timeToLive = this.endpointIdTimeToLive.apply(endpointId);
if (timeToLive != null && timeToLive > 0) { if (timeToLive != null && timeToLive > 0) {
......
...@@ -500,12 +500,12 @@ public class EndpointDiscovererTests { ...@@ -500,12 +500,12 @@ public class EndpointDiscovererTests {
} }
TestEndpointDiscoverer(ApplicationContext applicationContext, TestEndpointDiscoverer(ApplicationContext applicationContext,
Function<String, Long> timeToLive) { Function<EndpointId, Long> timeToLive) {
this(applicationContext, timeToLive, Collections.emptyList()); this(applicationContext, timeToLive, Collections.emptyList());
} }
TestEndpointDiscoverer(ApplicationContext applicationContext, TestEndpointDiscoverer(ApplicationContext applicationContext,
Function<String, Long> timeToLive, Function<EndpointId, Long> timeToLive,
Collection<EndpointFilter<TestExposableEndpoint>> filters) { Collection<EndpointFilter<TestExposableEndpoint>> filters) {
this(applicationContext, new ConversionServiceParameterValueMapper(), this(applicationContext, new ConversionServiceParameterValueMapper(),
Collections.singleton(new CachingOperationInvokerAdvisor(timeToLive)), Collections.singleton(new CachingOperationInvokerAdvisor(timeToLive)),
......
...@@ -51,7 +51,7 @@ public class CachingOperationInvokerAdvisorTests { ...@@ -51,7 +51,7 @@ public class CachingOperationInvokerAdvisorTests {
private OperationInvoker invoker; private OperationInvoker invoker;
@Mock @Mock
private Function<String, Long> timeToLive; private Function<EndpointId, Long> timeToLive;
private CachingOperationInvokerAdvisor advisor; private CachingOperationInvokerAdvisor advisor;
...@@ -85,7 +85,7 @@ public class CachingOperationInvokerAdvisorTests { ...@@ -85,7 +85,7 @@ public class CachingOperationInvokerAdvisorTests {
OperationInvoker advised = this.advisor.apply(EndpointId.of("foo"), OperationInvoker advised = this.advisor.apply(EndpointId.of("foo"),
OperationType.READ, parameters, this.invoker); OperationType.READ, parameters, this.invoker);
assertThat(advised).isSameAs(this.invoker); assertThat(advised).isSameAs(this.invoker);
verify(this.timeToLive).apply("foo"); verify(this.timeToLive).apply(EndpointId.of("foo"));
} }
@Test @Test
...@@ -95,7 +95,7 @@ public class CachingOperationInvokerAdvisorTests { ...@@ -95,7 +95,7 @@ public class CachingOperationInvokerAdvisorTests {
OperationInvoker advised = this.advisor.apply(EndpointId.of("foo"), OperationInvoker advised = this.advisor.apply(EndpointId.of("foo"),
OperationType.READ, parameters, this.invoker); OperationType.READ, parameters, this.invoker);
assertThat(advised).isSameAs(this.invoker); assertThat(advised).isSameAs(this.invoker);
verify(this.timeToLive).apply("foo"); verify(this.timeToLive).apply(EndpointId.of("foo"));
} }
@Test @Test
......
...@@ -306,7 +306,7 @@ public class JmxEndpointDiscovererTests { ...@@ -306,7 +306,7 @@ public class JmxEndpointDiscovererTests {
load(configuration, (id) -> null, consumer); load(configuration, (id) -> null, consumer);
} }
private void load(Class<?> configuration, Function<String, Long> timeToLive, private void load(Class<?> configuration, Function<EndpointId, Long> timeToLive,
Consumer<JmxEndpointDiscoverer> consumer) { Consumer<JmxEndpointDiscoverer> consumer) {
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
configuration)) { configuration)) {
......
...@@ -257,8 +257,9 @@ public class WebEndpointDiscovererTests { ...@@ -257,8 +257,9 @@ public class WebEndpointDiscovererTests {
this.load((id) -> null, (id) -> id, configuration, consumer); this.load((id) -> null, (id) -> id, configuration, consumer);
} }
private void load(Function<String, Long> timeToLive, PathMapper endpointPathMapper, private void load(Function<EndpointId, Long> timeToLive,
Class<?> configuration, Consumer<WebEndpointDiscoverer> consumer) { PathMapper endpointPathMapper, Class<?> configuration,
Consumer<WebEndpointDiscoverer> consumer) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
configuration); configuration);
try { try {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment