Merge branch '1.5.x' into 2.0.x

pull/17198/head
Andy Wilkinson 6 years ago
commit c6c139d980

@ -24,7 +24,7 @@
</property> </property>
</activation> </activation>
<properties> <properties>
<spring-javaformat.version>0.0.9</spring-javaformat.version> <spring-javaformat.version>0.0.11</spring-javaformat.version>
<nohttp-checkstyle.version>0.0.1.RELEASE</nohttp-checkstyle.version> <nohttp-checkstyle.version>0.0.1.RELEASE</nohttp-checkstyle.version>
</properties> </properties>
<build> <build>

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2019 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.
@ -40,15 +40,13 @@ public abstract class OnEndpointElementCondition extends SpringBootCondition {
private final Class<? extends Annotation> annotationType; private final Class<? extends Annotation> annotationType;
protected OnEndpointElementCondition(String prefix, protected OnEndpointElementCondition(String prefix, Class<? extends Annotation> annotationType) {
Class<? extends Annotation> annotationType) {
this.prefix = prefix; this.prefix = prefix;
this.annotationType = annotationType; this.annotationType = annotationType;
} }
@Override @Override
public ConditionOutcome getMatchOutcome(ConditionContext context, public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
AnnotatedTypeMetadata metadata) {
AnnotationAttributes annotationAttributes = AnnotationAttributes AnnotationAttributes annotationAttributes = AnnotationAttributes
.fromMap(metadata.getAnnotationAttributes(this.annotationType.getName())); .fromMap(metadata.getAnnotationAttributes(this.annotationType.getName()));
String endpointName = annotationAttributes.getString("value"); String endpointName = annotationAttributes.getString("value");
@ -59,25 +57,21 @@ public abstract class OnEndpointElementCondition extends SpringBootCondition {
return getDefaultEndpointsOutcome(context); return getDefaultEndpointsOutcome(context);
} }
protected ConditionOutcome getEndpointOutcome(ConditionContext context, protected ConditionOutcome getEndpointOutcome(ConditionContext context, String endpointName) {
String endpointName) {
Environment environment = context.getEnvironment(); Environment environment = context.getEnvironment();
String enabledProperty = this.prefix + endpointName + ".enabled"; String enabledProperty = this.prefix + endpointName + ".enabled";
if (environment.containsProperty(enabledProperty)) { if (environment.containsProperty(enabledProperty)) {
boolean match = environment.getProperty(enabledProperty, Boolean.class, true); boolean match = environment.getProperty(enabledProperty, Boolean.class, true);
return new ConditionOutcome(match, return new ConditionOutcome(match, ConditionMessage.forCondition(this.annotationType)
ConditionMessage.forCondition(this.annotationType).because( .because(this.prefix + endpointName + ".enabled is " + match));
this.prefix + endpointName + ".enabled is " + match));
} }
return null; return null;
} }
protected ConditionOutcome getDefaultEndpointsOutcome(ConditionContext context) { protected ConditionOutcome getDefaultEndpointsOutcome(ConditionContext context) {
boolean match = Boolean.valueOf(context.getEnvironment() boolean match = Boolean.valueOf(context.getEnvironment().getProperty(this.prefix + "defaults.enabled", "true"));
.getProperty(this.prefix + "defaults.enabled", "true")); return new ConditionOutcome(match, ConditionMessage.forCondition(this.annotationType)
return new ConditionOutcome(match, .because(this.prefix + "defaults.enabled is considered " + match));
ConditionMessage.forCondition(this.annotationType).because(
this.prefix + "defaults.enabled is considered " + match));
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2019 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.
@ -46,13 +46,12 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnEnabledHealthIndicator("rabbit") @ConditionalOnEnabledHealthIndicator("rabbit")
@AutoConfigureBefore(HealthIndicatorAutoConfiguration.class) @AutoConfigureBefore(HealthIndicatorAutoConfiguration.class)
@AutoConfigureAfter(RabbitAutoConfiguration.class) @AutoConfigureAfter(RabbitAutoConfiguration.class)
public class RabbitHealthIndicatorAutoConfiguration extends public class RabbitHealthIndicatorAutoConfiguration
CompositeHealthIndicatorConfiguration<RabbitHealthIndicator, RabbitTemplate> { extends CompositeHealthIndicatorConfiguration<RabbitHealthIndicator, RabbitTemplate> {
private final Map<String, RabbitTemplate> rabbitTemplates; private final Map<String, RabbitTemplate> rabbitTemplates;
public RabbitHealthIndicatorAutoConfiguration( public RabbitHealthIndicatorAutoConfiguration(Map<String, RabbitTemplate> rabbitTemplates) {
Map<String, RabbitTemplate> rabbitTemplates) {
this.rabbitTemplates = rabbitTemplates; this.rabbitTemplates = rabbitTemplates;
} }

@ -44,8 +44,7 @@ public class AuditAutoConfiguration {
private final AuditEventRepository auditEventRepository; private final AuditEventRepository auditEventRepository;
public AuditAutoConfiguration( public AuditAutoConfiguration(ObjectProvider<AuditEventRepository> auditEventRepository) {
ObjectProvider<AuditEventRepository> auditEventRepository) {
this.auditEventRepository = auditEventRepository.getIfAvailable(); this.auditEventRepository = auditEventRepository.getIfAvailable();
} }
@ -56,16 +55,14 @@ public class AuditAutoConfiguration {
} }
@Bean @Bean
@ConditionalOnClass( @ConditionalOnClass(name = "org.springframework.security.authentication.event.AbstractAuthenticationEvent")
name = "org.springframework.security.authentication.event.AbstractAuthenticationEvent")
@ConditionalOnMissingBean(AbstractAuthenticationAuditListener.class) @ConditionalOnMissingBean(AbstractAuthenticationAuditListener.class)
public AuthenticationAuditListener authenticationAuditListener() throws Exception { public AuthenticationAuditListener authenticationAuditListener() throws Exception {
return new AuthenticationAuditListener(); return new AuthenticationAuditListener();
} }
@Bean @Bean
@ConditionalOnClass( @ConditionalOnClass(name = "org.springframework.security.access.event.AbstractAuthorizationEvent")
name = "org.springframework.security.access.event.AbstractAuthorizationEvent")
@ConditionalOnMissingBean(AbstractAuthorizationAuditListener.class) @ConditionalOnMissingBean(AbstractAuthorizationAuditListener.class)
public AuthorizationAuditListener authorizationAuditListener() throws Exception { public AuthorizationAuditListener authorizationAuditListener() throws Exception {
return new AuthorizationAuditListener(); return new AuthorizationAuditListener();

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -43,8 +43,7 @@ public class AuditEventsEndpointAutoConfiguration {
@ConditionalOnMissingBean @ConditionalOnMissingBean
@ConditionalOnBean(AuditEventRepository.class) @ConditionalOnBean(AuditEventRepository.class)
@ConditionalOnEnabledEndpoint @ConditionalOnEnabledEndpoint
public AuditEventsEndpoint auditEventsEndpoint( public AuditEventsEndpoint auditEventsEndpoint(AuditEventRepository auditEventRepository) {
AuditEventRepository auditEventRepository) {
return new AuditEventsEndpoint(auditEventRepository); return new AuditEventsEndpoint(auditEventRepository);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2019 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.
@ -36,8 +36,7 @@ public class BeansEndpointAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint @ConditionalOnEnabledEndpoint
public BeansEndpoint beansEndpoint( public BeansEndpoint beansEndpoint(ConfigurableApplicationContext applicationContext) {
ConfigurableApplicationContext applicationContext) {
return new BeansEndpoint(applicationContext); return new BeansEndpoint(applicationContext);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2019 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.
@ -49,15 +49,13 @@ import org.springframework.data.cassandra.core.CassandraOperations;
@ConditionalOnBean(CassandraOperations.class) @ConditionalOnBean(CassandraOperations.class)
@ConditionalOnEnabledHealthIndicator("cassandra") @ConditionalOnEnabledHealthIndicator("cassandra")
@AutoConfigureBefore(HealthIndicatorAutoConfiguration.class) @AutoConfigureBefore(HealthIndicatorAutoConfiguration.class)
@AutoConfigureAfter({ CassandraAutoConfiguration.class, @AutoConfigureAfter({ CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class })
CassandraDataAutoConfiguration.class }) public class CassandraHealthIndicatorAutoConfiguration
public class CassandraHealthIndicatorAutoConfiguration extends extends CompositeHealthIndicatorConfiguration<CassandraHealthIndicator, CassandraOperations> {
CompositeHealthIndicatorConfiguration<CassandraHealthIndicator, CassandraOperations> {
private final Map<String, CassandraOperations> cassandraOperations; private final Map<String, CassandraOperations> cassandraOperations;
public CassandraHealthIndicatorAutoConfiguration( public CassandraHealthIndicatorAutoConfiguration(Map<String, CassandraOperations> cassandraOperations) {
Map<String, CassandraOperations> cassandraOperations) {
this.cassandraOperations = cassandraOperations; this.cassandraOperations = cassandraOperations;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -32,8 +32,7 @@ public class CloudFoundryAuthorizationException extends RuntimeException {
this(reason, message, null); this(reason, message, null);
} }
public CloudFoundryAuthorizationException(Reason reason, String message, public CloudFoundryAuthorizationException(Reason reason, String message, Throwable cause) {
Throwable cause) {
super(message, cause); super(message, cause);
this.reason = reason; this.reason = reason;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -50,18 +50,16 @@ public class CloudFoundryWebEndpointDiscoverer extends WebEndpointDiscoverer {
* @param filters filters to apply * @param filters filters to apply
*/ */
public CloudFoundryWebEndpointDiscoverer(ApplicationContext applicationContext, public CloudFoundryWebEndpointDiscoverer(ApplicationContext applicationContext,
ParameterValueMapper parameterValueMapper, ParameterValueMapper parameterValueMapper, EndpointMediaTypes endpointMediaTypes,
EndpointMediaTypes endpointMediaTypes, PathMapper endpointPathMapper, PathMapper endpointPathMapper, Collection<OperationInvokerAdvisor> invokerAdvisors,
Collection<OperationInvokerAdvisor> invokerAdvisors,
Collection<EndpointFilter<ExposableWebEndpoint>> filters) { Collection<EndpointFilter<ExposableWebEndpoint>> filters) {
super(applicationContext, parameterValueMapper, endpointMediaTypes, super(applicationContext, parameterValueMapper, endpointMediaTypes, endpointPathMapper, invokerAdvisors,
endpointPathMapper, invokerAdvisors, filters); filters);
} }
@Override @Override
protected boolean isExtensionExposed(Object extensionBean) { protected boolean isExtensionExposed(Object extensionBean) {
if (isHealthEndpointExtension(extensionBean) if (isHealthEndpointExtension(extensionBean) && !isCloudFoundryHealthEndpointExtension(extensionBean)) {
&& !isCloudFoundryHealthEndpointExtension(extensionBean)) {
// Filter regular health endpoint extensions so a CF version can replace them // Filter regular health endpoint extensions so a CF version can replace them
return false; return false;
} }
@ -69,16 +67,14 @@ public class CloudFoundryWebEndpointDiscoverer extends WebEndpointDiscoverer {
} }
private boolean isHealthEndpointExtension(Object extensionBean) { private boolean isHealthEndpointExtension(Object extensionBean) {
AnnotationAttributes attributes = AnnotatedElementUtils AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(extensionBean.getClass(),
.getMergedAnnotationAttributes(extensionBean.getClass(),
EndpointWebExtension.class); EndpointWebExtension.class);
Class<?> endpoint = (attributes != null) ? attributes.getClass("endpoint") : null; Class<?> endpoint = (attributes != null) ? attributes.getClass("endpoint") : null;
return (endpoint != null && HealthEndpoint.class.isAssignableFrom(endpoint)); return (endpoint != null && HealthEndpoint.class.isAssignableFrom(endpoint));
} }
private boolean isCloudFoundryHealthEndpointExtension(Object extensionBean) { private boolean isCloudFoundryHealthEndpointExtension(Object extensionBean) {
return AnnotatedElementUtils.hasAnnotation(extensionBean.getClass(), return AnnotatedElementUtils.hasAnnotation(extensionBean.getClass(), HealthEndpointCloudFoundryExtension.class);
HealthEndpointCloudFoundryExtension.class);
} }
} }

@ -35,8 +35,7 @@ import org.springframework.boot.actuate.health.HealthEndpoint;
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
@EndpointExtension(filter = CloudFoundryEndpointFilter.class, @EndpointExtension(filter = CloudFoundryEndpointFilter.class, endpoint = HealthEndpoint.class)
endpoint = HealthEndpoint.class)
public @interface HealthEndpointCloudFoundryExtension { public @interface HealthEndpointCloudFoundryExtension {
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -61,12 +61,10 @@ public class Token {
private Map<String, Object> parseJson(String base64) { private Map<String, Object> parseJson(String base64) {
try { try {
byte[] bytes = Base64Utils.decodeFromUrlSafeString(base64); byte[] bytes = Base64Utils.decodeFromUrlSafeString(base64);
return JsonParserFactory.getJsonParser() return JsonParserFactory.getJsonParser().parseMap(new String(bytes, StandardCharsets.UTF_8));
.parseMap(new String(bytes, StandardCharsets.UTF_8));
} }
catch (RuntimeException ex) { catch (RuntimeException ex) {
throw new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN, throw new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN, "Token could not be parsed", ex);
"Token could not be parsed", ex);
} }
} }
@ -103,8 +101,7 @@ public class Token {
private <T> T getRequired(Map<String, Object> map, String key, Class<T> type) { private <T> T getRequired(Map<String, Object> map, String key, Class<T> type) {
Object value = map.get(key); Object value = map.get(key);
if (value == null) { if (value == null) {
throw new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN, throw new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN, "Unable to get value from key " + key);
"Unable to get value from key " + key);
} }
if (!type.isInstance(value)) { if (!type.isInstance(value)) {
throw new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN, throw new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN,

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -39,8 +39,7 @@ public class CloudFoundryReactiveHealthEndpointWebExtension {
private final ReactiveHealthEndpointWebExtension delegate; private final ReactiveHealthEndpointWebExtension delegate;
public CloudFoundryReactiveHealthEndpointWebExtension( public CloudFoundryReactiveHealthEndpointWebExtension(ReactiveHealthEndpointWebExtension delegate) {
ReactiveHealthEndpointWebExtension delegate) {
this.delegate = delegate; this.delegate = delegate;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -39,8 +39,7 @@ import org.springframework.web.server.ServerWebExchange;
*/ */
class CloudFoundrySecurityInterceptor { class CloudFoundrySecurityInterceptor {
private static final Log logger = LogFactory private static final Log logger = LogFactory.getLog(CloudFoundrySecurityInterceptor.class);
.getLog(CloudFoundrySecurityInterceptor.class);
private final ReactiveTokenValidator tokenValidator; private final ReactiveTokenValidator tokenValidator;
@ -48,12 +47,10 @@ class CloudFoundrySecurityInterceptor {
private final String applicationId; private final String applicationId;
private static final Mono<SecurityResponse> SUCCESS = Mono private static final Mono<SecurityResponse> SUCCESS = Mono.just(SecurityResponse.success());
.just(SecurityResponse.success());
CloudFoundrySecurityInterceptor(ReactiveTokenValidator tokenValidator, CloudFoundrySecurityInterceptor(ReactiveTokenValidator tokenValidator,
ReactiveCloudFoundrySecurityService cloudFoundrySecurityService, ReactiveCloudFoundrySecurityService cloudFoundrySecurityService, String applicationId) {
String applicationId) {
this.tokenValidator = tokenValidator; this.tokenValidator = tokenValidator;
this.cloudFoundrySecurityService = cloudFoundrySecurityService; this.cloudFoundrySecurityService = cloudFoundrySecurityService;
this.applicationId = applicationId; this.applicationId = applicationId;
@ -65,15 +62,14 @@ class CloudFoundrySecurityInterceptor {
return SUCCESS; return SUCCESS;
} }
if (!StringUtils.hasText(this.applicationId)) { if (!StringUtils.hasText(this.applicationId)) {
return Mono.error(new CloudFoundryAuthorizationException( return Mono.error(new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,
Reason.SERVICE_UNAVAILABLE, "Application id is not available")); "Application id is not available"));
} }
if (this.cloudFoundrySecurityService == null) { if (this.cloudFoundrySecurityService == null) {
return Mono.error(new CloudFoundryAuthorizationException( return Mono.error(new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,
Reason.SERVICE_UNAVAILABLE, "Cloud controller URL is not available")); "Cloud controller URL is not available"));
} }
return check(exchange, id).then(SUCCESS).doOnError(this::logError) return check(exchange, id).then(SUCCESS).doOnError(this::logError).onErrorResume(this::getErrorResponse);
.onErrorResume(this::getErrorResponse);
} }
private void logError(Throwable ex) { private void logError(Throwable ex) {
@ -84,13 +80,11 @@ class CloudFoundrySecurityInterceptor {
try { try {
Token token = getToken(exchange.getRequest()); Token token = getToken(exchange.getRequest());
return this.tokenValidator.validate(token) return this.tokenValidator.validate(token)
.then(this.cloudFoundrySecurityService .then(this.cloudFoundrySecurityService.getAccessLevel(token.toString(), this.applicationId))
.getAccessLevel(token.toString(), this.applicationId))
.filter((accessLevel) -> accessLevel.isAccessAllowed(id)) .filter((accessLevel) -> accessLevel.isAccessAllowed(id))
.switchIfEmpty(Mono.error(new CloudFoundryAuthorizationException( .switchIfEmpty(
Reason.ACCESS_DENIED, "Access denied"))) Mono.error(new CloudFoundryAuthorizationException(Reason.ACCESS_DENIED, "Access denied")))
.doOnSuccess((accessLevel) -> exchange.getAttributes() .doOnSuccess((accessLevel) -> exchange.getAttributes().put("cloudFoundryAccessLevel", accessLevel))
.put("cloudFoundryAccessLevel", accessLevel))
.then(); .then();
} }
catch (CloudFoundryAuthorizationException ex) { catch (CloudFoundryAuthorizationException ex) {
@ -104,15 +98,13 @@ class CloudFoundrySecurityInterceptor {
return Mono.just(new SecurityResponse(cfException.getStatusCode(), return Mono.just(new SecurityResponse(cfException.getStatusCode(),
"{\"security_error\":\"" + cfException.getMessage() + "\"}")); "{\"security_error\":\"" + cfException.getMessage() + "\"}"));
} }
return Mono.just(new SecurityResponse(HttpStatus.INTERNAL_SERVER_ERROR, return Mono.just(new SecurityResponse(HttpStatus.INTERNAL_SERVER_ERROR, throwable.getMessage()));
throwable.getMessage()));
} }
private Token getToken(ServerHttpRequest request) { private Token getToken(ServerHttpRequest request) {
String authorization = request.getHeaders().getFirst("Authorization"); String authorization = request.getHeaders().getFirst("Authorization");
String bearerPrefix = "bearer "; String bearerPrefix = "bearer ";
if (authorization == null if (authorization == null || !authorization.toLowerCase(Locale.ENGLISH).startsWith(bearerPrefix)) {
|| !authorization.toLowerCase(Locale.ENGLISH).startsWith(bearerPrefix)) {
throw new CloudFoundryAuthorizationException(Reason.MISSING_AUTHORIZATION, throw new CloudFoundryAuthorizationException(Reason.MISSING_AUTHORIZATION,
"Authorization header is missing or invalid"); "Authorization header is missing or invalid");
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -50,17 +50,15 @@ import org.springframework.web.server.ServerWebExchange;
* @author Madhura Bhave * @author Madhura Bhave
* @author Phillip Webb * @author Phillip Webb
*/ */
class CloudFoundryWebFluxEndpointHandlerMapping class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointHandlerMapping {
extends AbstractWebFluxEndpointHandlerMapping {
private final CloudFoundrySecurityInterceptor securityInterceptor; private final CloudFoundrySecurityInterceptor securityInterceptor;
private final EndpointLinksResolver linksResolver; private final EndpointLinksResolver linksResolver;
CloudFoundryWebFluxEndpointHandlerMapping(EndpointMapping endpointMapping, CloudFoundryWebFluxEndpointHandlerMapping(EndpointMapping endpointMapping,
Collection<ExposableWebEndpoint> endpoints, Collection<ExposableWebEndpoint> endpoints, EndpointMediaTypes endpointMediaTypes,
EndpointMediaTypes endpointMediaTypes, CorsConfiguration corsConfiguration, CorsConfiguration corsConfiguration, CloudFoundrySecurityInterceptor securityInterceptor,
CloudFoundrySecurityInterceptor securityInterceptor,
EndpointLinksResolver linksResolver) { EndpointLinksResolver linksResolver) {
super(endpointMapping, endpoints, endpointMediaTypes, corsConfiguration); super(endpointMapping, endpoints, endpointMediaTypes, corsConfiguration);
this.linksResolver = linksResolver; this.linksResolver = linksResolver;
@ -68,40 +66,32 @@ class CloudFoundryWebFluxEndpointHandlerMapping
} }
@Override @Override
protected ReactiveWebOperation wrapReactiveWebOperation(ExposableWebEndpoint endpoint, protected ReactiveWebOperation wrapReactiveWebOperation(ExposableWebEndpoint endpoint, WebOperation operation,
WebOperation operation, ReactiveWebOperation reactiveWebOperation) { ReactiveWebOperation reactiveWebOperation) {
return new SecureReactiveWebOperation(reactiveWebOperation, return new SecureReactiveWebOperation(reactiveWebOperation, this.securityInterceptor, endpoint.getEndpointId());
this.securityInterceptor, endpoint.getEndpointId());
} }
@Override @Override
@ResponseBody @ResponseBody
protected Publisher<ResponseEntity<Object>> links(ServerWebExchange exchange) { protected Publisher<ResponseEntity<Object>> links(ServerWebExchange exchange) {
ServerHttpRequest request = exchange.getRequest(); ServerHttpRequest request = exchange.getRequest();
return this.securityInterceptor.preHandle(exchange, "") return this.securityInterceptor.preHandle(exchange, "").map((securityResponse) -> {
.map((securityResponse) -> {
if (!securityResponse.getStatus().equals(HttpStatus.OK)) { if (!securityResponse.getStatus().equals(HttpStatus.OK)) {
return new ResponseEntity<>(securityResponse.getStatus()); return new ResponseEntity<>(securityResponse.getStatus());
} }
AccessLevel accessLevel = exchange AccessLevel accessLevel = exchange.getAttribute(AccessLevel.REQUEST_ATTRIBUTE);
.getAttribute(AccessLevel.REQUEST_ATTRIBUTE); Map<String, Link> links = this.linksResolver.resolveLinks(request.getURI().toString());
Map<String, Link> links = this.linksResolver return new ResponseEntity<>(Collections.singletonMap("_links", getAccessibleLinks(accessLevel, links)),
.resolveLinks(request.getURI().toString());
return new ResponseEntity<>(
Collections.singletonMap("_links",
getAccessibleLinks(accessLevel, links)),
HttpStatus.OK); HttpStatus.OK);
}); });
} }
private Map<String, Link> getAccessibleLinks(AccessLevel accessLevel, private Map<String, Link> getAccessibleLinks(AccessLevel accessLevel, Map<String, Link> links) {
Map<String, Link> links) {
if (accessLevel == null) { if (accessLevel == null) {
return new LinkedHashMap<>(); return new LinkedHashMap<>();
} }
return links.entrySet().stream() return links.entrySet().stream()
.filter((entry) -> entry.getKey().equals("self") .filter((entry) -> entry.getKey().equals("self") || accessLevel.isAccessAllowed(entry.getKey()))
|| accessLevel.isAccessAllowed(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
} }
@ -116,8 +106,7 @@ class CloudFoundryWebFluxEndpointHandlerMapping
private final EndpointId endpointId; private final EndpointId endpointId;
SecureReactiveWebOperation(ReactiveWebOperation delegate, SecureReactiveWebOperation(ReactiveWebOperation delegate, CloudFoundrySecurityInterceptor securityInterceptor,
CloudFoundrySecurityInterceptor securityInterceptor,
EndpointId endpointId) { EndpointId endpointId) {
this.delegate = delegate; this.delegate = delegate;
this.securityInterceptor = securityInterceptor; this.securityInterceptor = securityInterceptor;
@ -125,16 +114,13 @@ class CloudFoundryWebFluxEndpointHandlerMapping
} }
@Override @Override
public Mono<ResponseEntity<Object>> handle(ServerWebExchange exchange, public Mono<ResponseEntity<Object>> handle(ServerWebExchange exchange, Map<String, String> body) {
Map<String, String> body) { return this.securityInterceptor.preHandle(exchange, this.endpointId.toLowerCaseString())
return this.securityInterceptor .flatMap((securityResponse) -> flatMapResponse(exchange, body, securityResponse));
.preHandle(exchange, this.endpointId.toLowerCaseString())
.flatMap((securityResponse) -> flatMapResponse(exchange, body,
securityResponse));
} }
private Mono<ResponseEntity<Object>> flatMapResponse(ServerWebExchange exchange, private Mono<ResponseEntity<Object>> flatMapResponse(ServerWebExchange exchange, Map<String, String> body,
Map<String, String> body, SecurityResponse securityResponse) { SecurityResponse securityResponse) {
if (!securityResponse.getStatus().equals(HttpStatus.OK)) { if (!securityResponse.getStatus().equals(HttpStatus.OK)) {
return Mono.just(new ResponseEntity<>(securityResponse.getStatus())); return Mono.just(new ResponseEntity<>(securityResponse.getStatus()));
} }

@ -67,8 +67,7 @@ import org.springframework.web.server.WebFilter;
* @since 2.0.0 * @since 2.0.0
*/ */
@Configuration @Configuration
@ConditionalOnProperty(prefix = "management.cloudfoundry", name = "enabled", @ConditionalOnProperty(prefix = "management.cloudfoundry", name = "enabled", matchIfMissing = true)
matchIfMissing = true)
@AutoConfigureAfter(HealthEndpointAutoConfiguration.class) @AutoConfigureAfter(HealthEndpointAutoConfiguration.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnCloudPlatform(CloudPlatform.CLOUD_FOUNDRY) @ConditionalOnCloudPlatform(CloudPlatform.CLOUD_FOUNDRY)
@ -86,58 +85,51 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration {
@ConditionalOnBean({ HealthEndpoint.class, ReactiveHealthEndpointWebExtension.class }) @ConditionalOnBean({ HealthEndpoint.class, ReactiveHealthEndpointWebExtension.class })
public CloudFoundryReactiveHealthEndpointWebExtension cloudFoundryReactiveHealthEndpointWebExtension( public CloudFoundryReactiveHealthEndpointWebExtension cloudFoundryReactiveHealthEndpointWebExtension(
ReactiveHealthEndpointWebExtension reactiveHealthEndpointWebExtension) { ReactiveHealthEndpointWebExtension reactiveHealthEndpointWebExtension) {
return new CloudFoundryReactiveHealthEndpointWebExtension( return new CloudFoundryReactiveHealthEndpointWebExtension(reactiveHealthEndpointWebExtension);
reactiveHealthEndpointWebExtension);
} }
@Bean @Bean
public CloudFoundryWebFluxEndpointHandlerMapping cloudFoundryWebFluxEndpointHandlerMapping( public CloudFoundryWebFluxEndpointHandlerMapping cloudFoundryWebFluxEndpointHandlerMapping(
ParameterValueMapper parameterMapper, EndpointMediaTypes endpointMediaTypes, ParameterValueMapper parameterMapper, EndpointMediaTypes endpointMediaTypes,
WebClient.Builder webClientBuilder, WebClient.Builder webClientBuilder, ControllerEndpointsSupplier controllerEndpointsSupplier) {
ControllerEndpointsSupplier controllerEndpointsSupplier) {
CloudFoundryWebEndpointDiscoverer endpointDiscoverer = new CloudFoundryWebEndpointDiscoverer( CloudFoundryWebEndpointDiscoverer endpointDiscoverer = new CloudFoundryWebEndpointDiscoverer(
this.applicationContext, parameterMapper, endpointMediaTypes, this.applicationContext, parameterMapper, endpointMediaTypes, PathMapper.useEndpointId(),
PathMapper.useEndpointId(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
Collections.emptyList()); CloudFoundrySecurityInterceptor securityInterceptor = getSecurityInterceptor(webClientBuilder,
CloudFoundrySecurityInterceptor securityInterceptor = getSecurityInterceptor( this.applicationContext.getEnvironment());
webClientBuilder, this.applicationContext.getEnvironment());
Collection<ExposableWebEndpoint> webEndpoints = endpointDiscoverer.getEndpoints(); Collection<ExposableWebEndpoint> webEndpoints = endpointDiscoverer.getEndpoints();
List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>(); List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
allEndpoints.addAll(webEndpoints); allEndpoints.addAll(webEndpoints);
allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints()); allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
return new CloudFoundryWebFluxEndpointHandlerMapping( return new CloudFoundryWebFluxEndpointHandlerMapping(new EndpointMapping("/cloudfoundryapplication"),
new EndpointMapping("/cloudfoundryapplication"), webEndpoints, webEndpoints, endpointMediaTypes, getCorsConfiguration(), securityInterceptor,
endpointMediaTypes, getCorsConfiguration(), securityInterceptor,
new EndpointLinksResolver(allEndpoints)); new EndpointLinksResolver(allEndpoints));
} }
private CloudFoundrySecurityInterceptor getSecurityInterceptor( private CloudFoundrySecurityInterceptor getSecurityInterceptor(WebClient.Builder webClientBuilder,
WebClient.Builder webClientBuilder, Environment environment) { Environment environment) {
ReactiveCloudFoundrySecurityService cloudfoundrySecurityService = getCloudFoundrySecurityService( ReactiveCloudFoundrySecurityService cloudfoundrySecurityService = getCloudFoundrySecurityService(
webClientBuilder, environment); webClientBuilder, environment);
ReactiveTokenValidator tokenValidator = new ReactiveTokenValidator( ReactiveTokenValidator tokenValidator = new ReactiveTokenValidator(cloudfoundrySecurityService);
cloudfoundrySecurityService); return new CloudFoundrySecurityInterceptor(tokenValidator, cloudfoundrySecurityService,
return new CloudFoundrySecurityInterceptor(tokenValidator,
cloudfoundrySecurityService,
environment.getProperty("vcap.application.application_id")); environment.getProperty("vcap.application.application_id"));
} }
private ReactiveCloudFoundrySecurityService getCloudFoundrySecurityService( private ReactiveCloudFoundrySecurityService getCloudFoundrySecurityService(WebClient.Builder webClientBuilder,
WebClient.Builder webClientBuilder, Environment environment) { Environment environment) {
String cloudControllerUrl = environment.getProperty("vcap.application.cf_api"); String cloudControllerUrl = environment.getProperty("vcap.application.cf_api");
boolean skipSslValidation = environment.getProperty( boolean skipSslValidation = environment.getProperty("management.cloudfoundry.skip-ssl-validation",
"management.cloudfoundry.skip-ssl-validation", Boolean.class, false); Boolean.class, false);
return (cloudControllerUrl != null) ? new ReactiveCloudFoundrySecurityService( return (cloudControllerUrl != null)
webClientBuilder, cloudControllerUrl, skipSslValidation) : null; ? new ReactiveCloudFoundrySecurityService(webClientBuilder, cloudControllerUrl, skipSslValidation)
: null;
} }
private CorsConfiguration getCorsConfiguration() { private CorsConfiguration getCorsConfiguration() {
CorsConfiguration corsConfiguration = new CorsConfiguration(); CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin(CorsConfiguration.ALL); corsConfiguration.addAllowedOrigin(CorsConfiguration.ALL);
corsConfiguration.setAllowedMethods( corsConfiguration.setAllowedMethods(Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name()));
Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name())); corsConfiguration.setAllowedHeaders(Arrays.asList("Authorization", "X-Cf-App-Instance", "Content-Type"));
corsConfiguration.setAllowedHeaders(
Arrays.asList("Authorization", "X-Cf-App-Instance", "Content-Type"));
return corsConfiguration; return corsConfiguration;
} }
@ -155,8 +147,7 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration {
private static class WebFilterChainPostProcessor implements BeanPostProcessor { private static class WebFilterChainPostProcessor implements BeanPostProcessor {
@Override @Override
public Object postProcessAfterInitialization(Object bean, String beanName) public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
throws BeansException {
if (bean instanceof WebFilterChainProxy) { if (bean instanceof WebFilterChainProxy) {
return postProcess((WebFilterChainProxy) bean); return postProcess((WebFilterChainProxy) bean);
} }
@ -170,10 +161,8 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration {
MatcherSecurityWebFilterChain ignoredRequestFilterChain = new MatcherSecurityWebFilterChain( MatcherSecurityWebFilterChain ignoredRequestFilterChain = new MatcherSecurityWebFilterChain(
cloudFoundryRequestMatcher, Collections.singletonList(noOpFilter)); cloudFoundryRequestMatcher, Collections.singletonList(noOpFilter));
MatcherSecurityWebFilterChain allRequestsFilterChain = new MatcherSecurityWebFilterChain( MatcherSecurityWebFilterChain allRequestsFilterChain = new MatcherSecurityWebFilterChain(
ServerWebExchangeMatchers.anyExchange(), ServerWebExchangeMatchers.anyExchange(), Collections.singletonList(existing));
Collections.singletonList(existing)); return new WebFilterChainProxy(ignoredRequestFilterChain, allRequestsFilterChain);
return new WebFilterChainProxy(ignoredRequestFilterChain,
allRequestsFilterChain);
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -52,8 +52,8 @@ class ReactiveCloudFoundrySecurityService {
private Mono<String> uaaUrl; private Mono<String> uaaUrl;
ReactiveCloudFoundrySecurityService(WebClient.Builder webClientBuilder, ReactiveCloudFoundrySecurityService(WebClient.Builder webClientBuilder, String cloudControllerUrl,
String cloudControllerUrl, boolean skipSslValidation) { boolean skipSslValidation) {
Assert.notNull(webClientBuilder, "Webclient must not be null"); Assert.notNull(webClientBuilder, "Webclient must not be null");
Assert.notNull(cloudControllerUrl, "CloudControllerUrl must not be null"); Assert.notNull(cloudControllerUrl, "CloudControllerUrl must not be null");
if (skipSslValidation) { if (skipSslValidation) {
@ -64,9 +64,8 @@ class ReactiveCloudFoundrySecurityService {
} }
protected ReactorClientHttpConnector buildTrustAllSslConnector() { protected ReactorClientHttpConnector buildTrustAllSslConnector() {
return new ReactorClientHttpConnector((options) -> options.sslSupport( return new ReactorClientHttpConnector((options) -> options.sslSupport((sslContextBuilder) -> sslContextBuilder
(sslContextBuilder) -> sslContextBuilder.sslProvider(SslProvider.JDK) .sslProvider(SslProvider.JDK).trustManager(InsecureTrustManagerFactory.INSTANCE)));
.trustManager(InsecureTrustManagerFactory.INSTANCE)));
} }
/** /**
@ -79,26 +78,21 @@ class ReactiveCloudFoundrySecurityService {
public Mono<AccessLevel> getAccessLevel(String token, String applicationId) public Mono<AccessLevel> getAccessLevel(String token, String applicationId)
throws CloudFoundryAuthorizationException { throws CloudFoundryAuthorizationException {
String uri = getPermissionsUri(applicationId); String uri = getPermissionsUri(applicationId);
return this.webClient.get().uri(uri).header("Authorization", "bearer " + token) return this.webClient.get().uri(uri).header("Authorization", "bearer " + token).retrieve().bodyToMono(Map.class)
.retrieve().bodyToMono(Map.class).map(this::getAccessLevel) .map(this::getAccessLevel).onErrorMap(this::mapError);
.onErrorMap(this::mapError);
} }
private Throwable mapError(Throwable throwable) { private Throwable mapError(Throwable throwable) {
if (throwable instanceof WebClientResponseException) { if (throwable instanceof WebClientResponseException) {
HttpStatus statusCode = ((WebClientResponseException) throwable) HttpStatus statusCode = ((WebClientResponseException) throwable).getStatusCode();
.getStatusCode();
if (statusCode.equals(HttpStatus.FORBIDDEN)) { if (statusCode.equals(HttpStatus.FORBIDDEN)) {
return new CloudFoundryAuthorizationException(Reason.ACCESS_DENIED, return new CloudFoundryAuthorizationException(Reason.ACCESS_DENIED, "Access denied");
"Access denied");
} }
if (statusCode.is4xxClientError()) { if (statusCode.is4xxClientError()) {
return new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN, return new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN, "Invalid token", throwable);
"Invalid token", throwable);
} }
} }
return new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE, return new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE, "Cloud controller not reachable");
"Cloud controller not reachable");
} }
private AccessLevel getAccessLevel(Map<?, ?> body) { private AccessLevel getAccessLevel(Map<?, ?> body) {
@ -122,9 +116,8 @@ class ReactiveCloudFoundrySecurityService {
private Mono<? extends Map<String, String>> fetchTokenKeys(String url) { private Mono<? extends Map<String, String>> fetchTokenKeys(String url) {
RequestHeadersSpec<?> uri = this.webClient.get().uri(url + "/token_keys"); RequestHeadersSpec<?> uri = this.webClient.get().uri(url + "/token_keys");
return uri.retrieve().bodyToMono(STRING_OBJECT_MAP).map(this::extractTokenKeys) return uri.retrieve().bodyToMono(STRING_OBJECT_MAP).map(this::extractTokenKeys).onErrorMap(
.onErrorMap(((ex) -> new CloudFoundryAuthorizationException( ((ex) -> new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE, ex.getMessage())));
Reason.SERVICE_UNAVAILABLE, ex.getMessage())));
} }
private Map<String, String> extractTokenKeys(Map<String, Object> response) { private Map<String, String> extractTokenKeys(Map<String, Object> response) {
@ -141,11 +134,9 @@ class ReactiveCloudFoundrySecurityService {
* @return the UAA url Mono * @return the UAA url Mono
*/ */
public Mono<String> getUaaUrl() { public Mono<String> getUaaUrl() {
this.uaaUrl = this.webClient.get().uri(this.cloudControllerUrl + "/info") this.uaaUrl = this.webClient.get().uri(this.cloudControllerUrl + "/info").retrieve().bodyToMono(Map.class)
.retrieve().bodyToMono(Map.class)
.map((response) -> (String) response.get("token_endpoint")).cache() .map((response) -> (String) response.get("token_endpoint")).cache()
.onErrorMap((ex) -> new CloudFoundryAuthorizationException( .onErrorMap((ex) -> new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,
Reason.SERVICE_UNAVAILABLE,
"Unable to fetch token keys from UAA.")); "Unable to fetch token keys from UAA."));
return this.uaaUrl; return this.uaaUrl;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2019 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.
@ -51,20 +51,18 @@ class ReactiveTokenValidator {
} }
public Mono<Void> validate(Token token) { public Mono<Void> validate(Token token) {
return validateAlgorithm(token).then(validateKeyIdAndSignature(token)) return validateAlgorithm(token).then(validateKeyIdAndSignature(token)).then(validateExpiry(token))
.then(validateExpiry(token)).then(validateIssuer(token)) .then(validateIssuer(token)).then(validateAudience(token));
.then(validateAudience(token));
} }
private Mono<Void> validateAlgorithm(Token token) { private Mono<Void> validateAlgorithm(Token token) {
String algorithm = token.getSignatureAlgorithm(); String algorithm = token.getSignatureAlgorithm();
if (algorithm == null) { if (algorithm == null) {
return Mono.error(new CloudFoundryAuthorizationException( return Mono.error(new CloudFoundryAuthorizationException(Reason.INVALID_SIGNATURE,
Reason.INVALID_SIGNATURE, "Signing algorithm cannot be null")); "Signing algorithm cannot be null"));
} }
if (!algorithm.equals("RS256")) { if (!algorithm.equals("RS256")) {
return Mono.error(new CloudFoundryAuthorizationException( return Mono.error(new CloudFoundryAuthorizationException(Reason.UNSUPPORTED_TOKEN_SIGNING_ALGORITHM,
Reason.UNSUPPORTED_TOKEN_SIGNING_ALGORITHM,
"Signing algorithm " + algorithm + " not supported")); "Signing algorithm " + algorithm + " not supported"));
} }
return Mono.empty(); return Mono.empty();
@ -72,8 +70,8 @@ class ReactiveTokenValidator {
private Mono<Void> validateKeyIdAndSignature(Token token) { private Mono<Void> validateKeyIdAndSignature(Token token) {
return getTokenKey(token).filter((tokenKey) -> hasValidSignature(token, tokenKey)) return getTokenKey(token).filter((tokenKey) -> hasValidSignature(token, tokenKey))
.switchIfEmpty(Mono.error(new CloudFoundryAuthorizationException( .switchIfEmpty(Mono.error(new CloudFoundryAuthorizationException(Reason.INVALID_SIGNATURE,
Reason.INVALID_SIGNATURE, "RSA Signature did not match content"))) "RSA Signature did not match content")))
.then(); .then();
} }
@ -84,10 +82,8 @@ class ReactiveTokenValidator {
return Mono.just(cached); return Mono.just(cached);
} }
return this.securityService.fetchTokenKeys().doOnSuccess(this::cacheTokenKeys) return this.securityService.fetchTokenKeys().doOnSuccess(this::cacheTokenKeys)
.filter((tokenKeys) -> tokenKeys.containsKey(keyId)) .filter((tokenKeys) -> tokenKeys.containsKey(keyId)).map((tokenKeys) -> tokenKeys.get(keyId))
.map((tokenKeys) -> tokenKeys.get(keyId)) .switchIfEmpty(Mono.error(new CloudFoundryAuthorizationException(Reason.INVALID_KEY_ID,
.switchIfEmpty(Mono.error(
new CloudFoundryAuthorizationException(Reason.INVALID_KEY_ID,
"Key Id present in token header does not match"))); "Key Id present in token header does not match")));
} }
@ -108,8 +104,7 @@ class ReactiveTokenValidator {
} }
} }
private PublicKey getPublicKey(String key) private PublicKey getPublicKey(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {
throws NoSuchAlgorithmException, InvalidKeySpecException {
key = key.replace("-----BEGIN PUBLIC KEY-----\n", ""); key = key.replace("-----BEGIN PUBLIC KEY-----\n", "");
key = key.replace("-----END PUBLIC KEY-----", ""); key = key.replace("-----END PUBLIC KEY-----", "");
key = key.trim().replace("\n", ""); key = key.trim().replace("\n", "");
@ -121,25 +116,23 @@ class ReactiveTokenValidator {
private Mono<Void> validateExpiry(Token token) { private Mono<Void> validateExpiry(Token token) {
long currentTime = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()); long currentTime = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
if (currentTime > token.getExpiry()) { if (currentTime > token.getExpiry()) {
return Mono.error(new CloudFoundryAuthorizationException(Reason.TOKEN_EXPIRED, return Mono.error(new CloudFoundryAuthorizationException(Reason.TOKEN_EXPIRED, "Token expired"));
"Token expired"));
} }
return Mono.empty(); return Mono.empty();
} }
private Mono<Void> validateIssuer(Token token) { private Mono<Void> validateIssuer(Token token) {
return this.securityService.getUaaUrl() return this.securityService.getUaaUrl().map((uaaUrl) -> String.format("%s/oauth/token", uaaUrl))
.map((uaaUrl) -> String.format("%s/oauth/token", uaaUrl))
.filter((issuerUri) -> issuerUri.equals(token.getIssuer())) .filter((issuerUri) -> issuerUri.equals(token.getIssuer()))
.switchIfEmpty(Mono.error(new CloudFoundryAuthorizationException( .switchIfEmpty(Mono.error(
Reason.INVALID_ISSUER, "Token issuer does not match"))) new CloudFoundryAuthorizationException(Reason.INVALID_ISSUER, "Token issuer does not match")))
.then(); .then();
} }
private Mono<Void> validateAudience(Token token) { private Mono<Void> validateAudience(Token token) {
if (!token.getScope().contains("actuator.read")) { if (!token.getScope().contains("actuator.read")) {
return Mono.error(new CloudFoundryAuthorizationException( return Mono.error(new CloudFoundryAuthorizationException(Reason.INVALID_AUDIENCE,
Reason.INVALID_AUDIENCE, "Token does not have audience actuator")); "Token does not have audience actuator"));
} }
return Mono.empty(); return Mono.empty();
} }

@ -68,10 +68,8 @@ import org.springframework.web.servlet.DispatcherServlet;
* @since 2.0.0 * @since 2.0.0
*/ */
@Configuration @Configuration
@ConditionalOnProperty(prefix = "management.cloudfoundry", name = "enabled", @ConditionalOnProperty(prefix = "management.cloudfoundry", name = "enabled", matchIfMissing = true)
matchIfMissing = true) @AutoConfigureAfter({ ServletManagementContextAutoConfiguration.class, HealthEndpointAutoConfiguration.class })
@AutoConfigureAfter({ ServletManagementContextAutoConfiguration.class,
HealthEndpointAutoConfiguration.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class) @ConditionalOnClass(DispatcherServlet.class)
@ConditionalOnBean(DispatcherServlet.class) @ConditionalOnBean(DispatcherServlet.class)
@ -96,52 +94,46 @@ public class CloudFoundryActuatorAutoConfiguration {
@Bean @Bean
public CloudFoundryWebEndpointServletHandlerMapping cloudFoundryWebEndpointServletHandlerMapping( public CloudFoundryWebEndpointServletHandlerMapping cloudFoundryWebEndpointServletHandlerMapping(
ParameterValueMapper parameterMapper, EndpointMediaTypes endpointMediaTypes, ParameterValueMapper parameterMapper, EndpointMediaTypes endpointMediaTypes,
RestTemplateBuilder restTemplateBuilder, RestTemplateBuilder restTemplateBuilder, ServletEndpointsSupplier servletEndpointsSupplier,
ServletEndpointsSupplier servletEndpointsSupplier,
ControllerEndpointsSupplier controllerEndpointsSupplier) { ControllerEndpointsSupplier controllerEndpointsSupplier) {
CloudFoundryWebEndpointDiscoverer discoverer = new CloudFoundryWebEndpointDiscoverer( CloudFoundryWebEndpointDiscoverer discoverer = new CloudFoundryWebEndpointDiscoverer(this.applicationContext,
this.applicationContext, parameterMapper, endpointMediaTypes, parameterMapper, endpointMediaTypes, PathMapper.useEndpointId(), Collections.emptyList(),
PathMapper.useEndpointId(), Collections.emptyList(),
Collections.emptyList()); Collections.emptyList());
CloudFoundrySecurityInterceptor securityInterceptor = getSecurityInterceptor( CloudFoundrySecurityInterceptor securityInterceptor = getSecurityInterceptor(restTemplateBuilder,
restTemplateBuilder, this.applicationContext.getEnvironment()); this.applicationContext.getEnvironment());
Collection<ExposableWebEndpoint> webEndpoints = discoverer.getEndpoints(); Collection<ExposableWebEndpoint> webEndpoints = discoverer.getEndpoints();
List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>(); List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
allEndpoints.addAll(webEndpoints); allEndpoints.addAll(webEndpoints);
allEndpoints.addAll(servletEndpointsSupplier.getEndpoints()); allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints()); allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
return new CloudFoundryWebEndpointServletHandlerMapping( return new CloudFoundryWebEndpointServletHandlerMapping(new EndpointMapping("/cloudfoundryapplication"),
new EndpointMapping("/cloudfoundryapplication"), webEndpoints, webEndpoints, endpointMediaTypes, getCorsConfiguration(), securityInterceptor,
endpointMediaTypes, getCorsConfiguration(), securityInterceptor,
new EndpointLinksResolver(allEndpoints)); new EndpointLinksResolver(allEndpoints));
} }
private CloudFoundrySecurityInterceptor getSecurityInterceptor( private CloudFoundrySecurityInterceptor getSecurityInterceptor(RestTemplateBuilder restTemplateBuilder,
RestTemplateBuilder restTemplateBuilder, Environment environment) { Environment environment) {
CloudFoundrySecurityService cloudfoundrySecurityService = getCloudFoundrySecurityService( CloudFoundrySecurityService cloudfoundrySecurityService = getCloudFoundrySecurityService(restTemplateBuilder,
restTemplateBuilder, environment); environment);
TokenValidator tokenValidator = new TokenValidator(cloudfoundrySecurityService); TokenValidator tokenValidator = new TokenValidator(cloudfoundrySecurityService);
return new CloudFoundrySecurityInterceptor(tokenValidator, return new CloudFoundrySecurityInterceptor(tokenValidator, cloudfoundrySecurityService,
cloudfoundrySecurityService,
environment.getProperty("vcap.application.application_id")); environment.getProperty("vcap.application.application_id"));
} }
private CloudFoundrySecurityService getCloudFoundrySecurityService( private CloudFoundrySecurityService getCloudFoundrySecurityService(RestTemplateBuilder restTemplateBuilder,
RestTemplateBuilder restTemplateBuilder, Environment environment) { Environment environment) {
String cloudControllerUrl = environment.getProperty("vcap.application.cf_api"); String cloudControllerUrl = environment.getProperty("vcap.application.cf_api");
boolean skipSslValidation = environment.getProperty( boolean skipSslValidation = environment.getProperty("management.cloudfoundry.skip-ssl-validation",
"management.cloudfoundry.skip-ssl-validation", Boolean.class, false); Boolean.class, false);
return (cloudControllerUrl != null) ? new CloudFoundrySecurityService( return (cloudControllerUrl != null)
restTemplateBuilder, cloudControllerUrl, skipSslValidation) : null; ? new CloudFoundrySecurityService(restTemplateBuilder, cloudControllerUrl, skipSslValidation) : null;
} }
private CorsConfiguration getCorsConfiguration() { private CorsConfiguration getCorsConfiguration() {
CorsConfiguration corsConfiguration = new CorsConfiguration(); CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin(CorsConfiguration.ALL); corsConfiguration.addAllowedOrigin(CorsConfiguration.ALL);
corsConfiguration.setAllowedMethods( corsConfiguration.setAllowedMethods(Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name()));
Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name())); corsConfiguration.setAllowedHeaders(Arrays.asList("Authorization", "X-Cf-App-Instance", "Content-Type"));
corsConfiguration.setAllowedHeaders(
Arrays.asList("Authorization", "X-Cf-App-Instance", "Content-Type"));
return corsConfiguration; return corsConfiguration;
} }
@ -153,13 +145,11 @@ public class CloudFoundryActuatorAutoConfiguration {
@ConditionalOnClass(WebSecurity.class) @ConditionalOnClass(WebSecurity.class)
@Order(SecurityProperties.IGNORED_ORDER) @Order(SecurityProperties.IGNORED_ORDER)
@Configuration @Configuration
public static class IgnoredPathsWebSecurityConfigurer public static class IgnoredPathsWebSecurityConfigurer implements WebSecurityConfigurer<WebSecurity> {
implements WebSecurityConfigurer<WebSecurity> {
@Override @Override
public void init(WebSecurity builder) throws Exception { public void init(WebSecurity builder) throws Exception {
builder.ignoring().requestMatchers( builder.ignoring().requestMatchers(new AntPathRequestMatcher("/cloudfoundryapplication/**"));
new AntPathRequestMatcher("/cloudfoundryapplication/**"));
} }
@Override @Override

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -41,8 +41,7 @@ import org.springframework.web.cors.CorsUtils;
*/ */
class CloudFoundrySecurityInterceptor { class CloudFoundrySecurityInterceptor {
private static final Log logger = LogFactory private static final Log logger = LogFactory.getLog(CloudFoundrySecurityInterceptor.class);
.getLog(CloudFoundrySecurityInterceptor.class);
private final TokenValidator tokenValidator; private final TokenValidator tokenValidator;
@ -53,8 +52,7 @@ class CloudFoundrySecurityInterceptor {
private static final SecurityResponse SUCCESS = SecurityResponse.success(); private static final SecurityResponse SUCCESS = SecurityResponse.success();
CloudFoundrySecurityInterceptor(TokenValidator tokenValidator, CloudFoundrySecurityInterceptor(TokenValidator tokenValidator,
CloudFoundrySecurityService cloudFoundrySecurityService, CloudFoundrySecurityService cloudFoundrySecurityService, String applicationId) {
String applicationId) {
this.tokenValidator = tokenValidator; this.tokenValidator = tokenValidator;
this.cloudFoundrySecurityService = cloudFoundrySecurityService; this.cloudFoundrySecurityService = cloudFoundrySecurityService;
this.applicationId = applicationId; this.applicationId = applicationId;
@ -85,22 +83,17 @@ class CloudFoundrySecurityInterceptor {
return new SecurityResponse(cfException.getStatusCode(), return new SecurityResponse(cfException.getStatusCode(),
"{\"security_error\":\"" + cfException.getMessage() + "\"}"); "{\"security_error\":\"" + cfException.getMessage() + "\"}");
} }
return new SecurityResponse(HttpStatus.INTERNAL_SERVER_ERROR, return new SecurityResponse(HttpStatus.INTERNAL_SERVER_ERROR, ex.getMessage());
ex.getMessage());
} }
return SecurityResponse.success(); return SecurityResponse.success();
} }
private void check(HttpServletRequest request, EndpointId endpointId) private void check(HttpServletRequest request, EndpointId endpointId) throws Exception {
throws Exception {
Token token = getToken(request); Token token = getToken(request);
this.tokenValidator.validate(token); this.tokenValidator.validate(token);
AccessLevel accessLevel = this.cloudFoundrySecurityService AccessLevel accessLevel = this.cloudFoundrySecurityService.getAccessLevel(token.toString(), this.applicationId);
.getAccessLevel(token.toString(), this.applicationId); if (!accessLevel.isAccessAllowed((endpointId != null) ? endpointId.toLowerCaseString() : "")) {
if (!accessLevel.isAccessAllowed( throw new CloudFoundryAuthorizationException(Reason.ACCESS_DENIED, "Access denied");
(endpointId != null) ? endpointId.toLowerCaseString() : "")) {
throw new CloudFoundryAuthorizationException(Reason.ACCESS_DENIED,
"Access denied");
} }
request.setAttribute(AccessLevel.REQUEST_ATTRIBUTE, accessLevel); request.setAttribute(AccessLevel.REQUEST_ATTRIBUTE, accessLevel);
} }
@ -108,8 +101,7 @@ class CloudFoundrySecurityInterceptor {
private Token getToken(HttpServletRequest request) { private Token getToken(HttpServletRequest request) {
String authorization = request.getHeader("Authorization"); String authorization = request.getHeader("Authorization");
String bearerPrefix = "bearer "; String bearerPrefix = "bearer ";
if (authorization == null if (authorization == null || !authorization.toLowerCase(Locale.ENGLISH).startsWith(bearerPrefix)) {
|| !authorization.toLowerCase(Locale.ENGLISH).startsWith(bearerPrefix)) {
throw new CloudFoundryAuthorizationException(Reason.MISSING_AUTHORIZATION, throw new CloudFoundryAuthorizationException(Reason.MISSING_AUTHORIZATION,
"Authorization header is missing or invalid"); "Authorization header is missing or invalid");
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2019 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.
@ -47,13 +47,12 @@ class CloudFoundrySecurityService {
private String uaaUrl; private String uaaUrl;
CloudFoundrySecurityService(RestTemplateBuilder restTemplateBuilder, CloudFoundrySecurityService(RestTemplateBuilder restTemplateBuilder, String cloudControllerUrl,
String cloudControllerUrl, boolean skipSslValidation) { boolean skipSslValidation) {
Assert.notNull(restTemplateBuilder, "RestTemplateBuilder must not be null"); Assert.notNull(restTemplateBuilder, "RestTemplateBuilder must not be null");
Assert.notNull(cloudControllerUrl, "CloudControllerUrl must not be null"); Assert.notNull(cloudControllerUrl, "CloudControllerUrl must not be null");
if (skipSslValidation) { if (skipSslValidation) {
restTemplateBuilder = restTemplateBuilder restTemplateBuilder = restTemplateBuilder.requestFactory(SkipSslVerificationHttpRequestFactory.class);
.requestFactory(SkipSslVerificationHttpRequestFactory.class);
} }
this.restTemplate = restTemplateBuilder.build(); this.restTemplate = restTemplateBuilder.build();
this.cloudControllerUrl = cloudControllerUrl; this.cloudControllerUrl = cloudControllerUrl;
@ -66,12 +65,10 @@ class CloudFoundrySecurityService {
* @return the access level that should be granted * @return the access level that should be granted
* @throws CloudFoundryAuthorizationException if the token is not authorized * @throws CloudFoundryAuthorizationException if the token is not authorized
*/ */
public AccessLevel getAccessLevel(String token, String applicationId) public AccessLevel getAccessLevel(String token, String applicationId) throws CloudFoundryAuthorizationException {
throws CloudFoundryAuthorizationException {
try { try {
URI uri = getPermissionsUri(applicationId); URI uri = getPermissionsUri(applicationId);
RequestEntity<?> request = RequestEntity.get(uri) RequestEntity<?> request = RequestEntity.get(uri).header("Authorization", "bearer " + token).build();
.header("Authorization", "bearer " + token).build();
Map<?, ?> body = this.restTemplate.exchange(request, Map.class).getBody(); Map<?, ?> body = this.restTemplate.exchange(request, Map.class).getBody();
if (Boolean.TRUE.equals(body.get("read_sensitive_data"))) { if (Boolean.TRUE.equals(body.get("read_sensitive_data"))) {
return AccessLevel.FULL; return AccessLevel.FULL;
@ -80,22 +77,18 @@ class CloudFoundrySecurityService {
} }
catch (HttpClientErrorException ex) { catch (HttpClientErrorException ex) {
if (ex.getStatusCode().equals(HttpStatus.FORBIDDEN)) { if (ex.getStatusCode().equals(HttpStatus.FORBIDDEN)) {
throw new CloudFoundryAuthorizationException(Reason.ACCESS_DENIED, throw new CloudFoundryAuthorizationException(Reason.ACCESS_DENIED, "Access denied");
"Access denied");
} }
throw new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN, throw new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN, "Invalid token", ex);
"Invalid token", ex);
} }
catch (HttpServerErrorException ex) { catch (HttpServerErrorException ex) {
throw new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE, throw new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE, "Cloud controller not reachable");
"Cloud controller not reachable");
} }
} }
private URI getPermissionsUri(String applicationId) { private URI getPermissionsUri(String applicationId) {
try { try {
return new URI(this.cloudControllerUrl + "/v2/apps/" + applicationId return new URI(this.cloudControllerUrl + "/v2/apps/" + applicationId + "/permissions");
+ "/permissions");
} }
catch (URISyntaxException ex) { catch (URISyntaxException ex) {
throw new IllegalStateException(ex); throw new IllegalStateException(ex);
@ -108,12 +101,10 @@ class CloudFoundrySecurityService {
*/ */
public Map<String, String> fetchTokenKeys() { public Map<String, String> fetchTokenKeys() {
try { try {
return extractTokenKeys(this.restTemplate return extractTokenKeys(this.restTemplate.getForObject(getUaaUrl() + "/token_keys", Map.class));
.getForObject(getUaaUrl() + "/token_keys", Map.class));
} }
catch (HttpStatusCodeException ex) { catch (HttpStatusCodeException ex) {
throw new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE, throw new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE, "UAA not reachable");
"UAA not reachable");
} }
} }
@ -133,8 +124,7 @@ class CloudFoundrySecurityService {
public String getUaaUrl() { public String getUaaUrl() {
if (this.uaaUrl == null) { if (this.uaaUrl == null) {
try { try {
Map<?, ?> response = this.restTemplate Map<?, ?> response = this.restTemplate.getForObject(this.cloudControllerUrl + "/info", Map.class);
.getForObject(this.cloudControllerUrl + "/info", Map.class);
this.uaaUrl = (String) response.get("token_endpoint"); this.uaaUrl = (String) response.get("token_endpoint");
} }
catch (HttpStatusCodeException ex) { catch (HttpStatusCodeException ex) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -48,17 +48,15 @@ import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMappi
* @author Madhura Bhave * @author Madhura Bhave
* @author Phillip Webb * @author Phillip Webb
*/ */
class CloudFoundryWebEndpointServletHandlerMapping class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebMvcEndpointHandlerMapping {
extends AbstractWebMvcEndpointHandlerMapping {
private final CloudFoundrySecurityInterceptor securityInterceptor; private final CloudFoundrySecurityInterceptor securityInterceptor;
private final EndpointLinksResolver linksResolver; private final EndpointLinksResolver linksResolver;
CloudFoundryWebEndpointServletHandlerMapping(EndpointMapping endpointMapping, CloudFoundryWebEndpointServletHandlerMapping(EndpointMapping endpointMapping,
Collection<ExposableWebEndpoint> endpoints, Collection<ExposableWebEndpoint> endpoints, EndpointMediaTypes endpointMediaTypes,
EndpointMediaTypes endpointMediaTypes, CorsConfiguration corsConfiguration, CorsConfiguration corsConfiguration, CloudFoundrySecurityInterceptor securityInterceptor,
CloudFoundrySecurityInterceptor securityInterceptor,
EndpointLinksResolver linksResolver) { EndpointLinksResolver linksResolver) {
super(endpointMapping, endpoints, endpointMediaTypes, corsConfiguration); super(endpointMapping, endpoints, endpointMediaTypes, corsConfiguration);
this.securityInterceptor = securityInterceptor; this.securityInterceptor = securityInterceptor;
@ -66,41 +64,33 @@ class CloudFoundryWebEndpointServletHandlerMapping
} }
@Override @Override
protected ServletWebOperation wrapServletWebOperation(ExposableWebEndpoint endpoint, protected ServletWebOperation wrapServletWebOperation(ExposableWebEndpoint endpoint, WebOperation operation,
WebOperation operation, ServletWebOperation servletWebOperation) { ServletWebOperation servletWebOperation) {
return new SecureServletWebOperation(servletWebOperation, return new SecureServletWebOperation(servletWebOperation, this.securityInterceptor, endpoint.getEndpointId());
this.securityInterceptor, endpoint.getEndpointId());
} }
@Override @Override
@ResponseBody @ResponseBody
protected Map<String, Map<String, Link>> links(HttpServletRequest request, protected Map<String, Map<String, Link>> links(HttpServletRequest request, HttpServletResponse response) {
HttpServletResponse response) { SecurityResponse securityResponse = this.securityInterceptor.preHandle(request, null);
SecurityResponse securityResponse = this.securityInterceptor.preHandle(request,
null);
if (!securityResponse.getStatus().equals(HttpStatus.OK)) { if (!securityResponse.getStatus().equals(HttpStatus.OK)) {
sendFailureResponse(response, securityResponse); sendFailureResponse(response, securityResponse);
} }
AccessLevel accessLevel = (AccessLevel) request AccessLevel accessLevel = (AccessLevel) request.getAttribute(AccessLevel.REQUEST_ATTRIBUTE);
.getAttribute(AccessLevel.REQUEST_ATTRIBUTE); Map<String, Link> links = this.linksResolver.resolveLinks(request.getRequestURL().toString());
Map<String, Link> links = this.linksResolver
.resolveLinks(request.getRequestURL().toString());
Map<String, Link> filteredLinks = new LinkedHashMap<>(); Map<String, Link> filteredLinks = new LinkedHashMap<>();
if (accessLevel == null) { if (accessLevel == null) {
return Collections.singletonMap("_links", filteredLinks); return Collections.singletonMap("_links", filteredLinks);
} }
filteredLinks = links.entrySet().stream() filteredLinks = links.entrySet().stream()
.filter((e) -> e.getKey().equals("self") .filter((e) -> e.getKey().equals("self") || accessLevel.isAccessAllowed(e.getKey()))
|| accessLevel.isAccessAllowed(e.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
return Collections.singletonMap("_links", filteredLinks); return Collections.singletonMap("_links", filteredLinks);
} }
private void sendFailureResponse(HttpServletResponse response, private void sendFailureResponse(HttpServletResponse response, SecurityResponse securityResponse) {
SecurityResponse securityResponse) {
try { try {
response.sendError(securityResponse.getStatus().value(), response.sendError(securityResponse.getStatus().value(), securityResponse.getMessage());
securityResponse.getMessage());
} }
catch (Exception ex) { catch (Exception ex) {
this.logger.debug("Failed to send error response", ex); this.logger.debug("Failed to send error response", ex);
@ -118,8 +108,7 @@ class CloudFoundryWebEndpointServletHandlerMapping
private final EndpointId endpointId; private final EndpointId endpointId;
SecureServletWebOperation(ServletWebOperation delegate, SecureServletWebOperation(ServletWebOperation delegate, CloudFoundrySecurityInterceptor securityInterceptor,
CloudFoundrySecurityInterceptor securityInterceptor,
EndpointId endpointId) { EndpointId endpointId) {
this.delegate = delegate; this.delegate = delegate;
this.securityInterceptor = securityInterceptor; this.securityInterceptor = securityInterceptor;
@ -128,11 +117,9 @@ class CloudFoundryWebEndpointServletHandlerMapping
@Override @Override
public Object handle(HttpServletRequest request, Map<String, String> body) { public Object handle(HttpServletRequest request, Map<String, String> body) {
SecurityResponse securityResponse = this.securityInterceptor SecurityResponse securityResponse = this.securityInterceptor.preHandle(request, this.endpointId);
.preHandle(request, this.endpointId);
if (!securityResponse.getStatus().equals(HttpStatus.OK)) { if (!securityResponse.getStatus().equals(HttpStatus.OK)) {
return new ResponseEntity<Object>(securityResponse.getMessage(), return new ResponseEntity<Object>(securityResponse.getMessage(), securityResponse.getStatus());
securityResponse.getStatus());
} }
return this.delegate.handle(request, body); return this.delegate.handle(request, body);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2019 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.
@ -39,8 +39,7 @@ import org.springframework.http.client.SimpleClientHttpRequestFactory;
class SkipSslVerificationHttpRequestFactory extends SimpleClientHttpRequestFactory { class SkipSslVerificationHttpRequestFactory extends SimpleClientHttpRequestFactory {
@Override @Override
protected void prepareConnection(HttpURLConnection connection, String httpMethod) protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
throws IOException {
if (connection instanceof HttpsURLConnection) { if (connection instanceof HttpsURLConnection) {
prepareHttpsConnection((HttpsURLConnection) connection); prepareHttpsConnection((HttpsURLConnection) connection);
} }
@ -59,8 +58,7 @@ class SkipSslVerificationHttpRequestFactory extends SimpleClientHttpRequestFacto
private SSLSocketFactory createSslSocketFactory() throws Exception { private SSLSocketFactory createSslSocketFactory() throws Exception {
SSLContext context = SSLContext.getInstance("TLS"); SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new TrustManager[] { new SkipX509TrustManager() }, context.init(null, new TrustManager[] { new SkipX509TrustManager() }, new SecureRandom());
new SecureRandom());
return context.getSocketFactory(); return context.getSocketFactory();
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2019 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.
@ -57,12 +57,10 @@ class TokenValidator {
private void validateAlgorithm(Token token) { private void validateAlgorithm(Token token) {
String algorithm = token.getSignatureAlgorithm(); String algorithm = token.getSignatureAlgorithm();
if (algorithm == null) { if (algorithm == null) {
throw new CloudFoundryAuthorizationException(Reason.INVALID_SIGNATURE, throw new CloudFoundryAuthorizationException(Reason.INVALID_SIGNATURE, "Signing algorithm cannot be null");
"Signing algorithm cannot be null");
} }
if (!algorithm.equals("RS256")) { if (!algorithm.equals("RS256")) {
throw new CloudFoundryAuthorizationException( throw new CloudFoundryAuthorizationException(Reason.UNSUPPORTED_TOKEN_SIGNING_ALGORITHM,
Reason.UNSUPPORTED_TOKEN_SIGNING_ALGORITHM,
"Signing algorithm " + algorithm + " not supported"); "Signing algorithm " + algorithm + " not supported");
} }
} }
@ -105,8 +103,7 @@ class TokenValidator {
} }
} }
private PublicKey getPublicKey(String key) private PublicKey getPublicKey(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {
throws NoSuchAlgorithmException, InvalidKeySpecException {
key = key.replace("-----BEGIN PUBLIC KEY-----\n", ""); key = key.replace("-----BEGIN PUBLIC KEY-----\n", "");
key = key.replace("-----END PUBLIC KEY-----", ""); key = key.replace("-----END PUBLIC KEY-----", "");
key = key.trim().replace("\n", ""); key = key.trim().replace("\n", "");
@ -118,8 +115,7 @@ class TokenValidator {
private void validateExpiry(Token token) { private void validateExpiry(Token token) {
long currentTime = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()); long currentTime = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
if (currentTime > token.getExpiry()) { if (currentTime > token.getExpiry()) {
throw new CloudFoundryAuthorizationException(Reason.TOKEN_EXPIRED, throw new CloudFoundryAuthorizationException(Reason.TOKEN_EXPIRED, "Token expired");
"Token expired");
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -64,15 +64,13 @@ public class ConditionsReportEndpoint {
Map<String, ContextConditionEvaluation> contextConditionEvaluations = new HashMap<>(); Map<String, ContextConditionEvaluation> contextConditionEvaluations = new HashMap<>();
ConfigurableApplicationContext target = this.context; ConfigurableApplicationContext target = this.context;
while (target != null) { while (target != null) {
contextConditionEvaluations.put(target.getId(), contextConditionEvaluations.put(target.getId(), new ContextConditionEvaluation(target));
new ContextConditionEvaluation(target));
target = getConfigurableParent(target); target = getConfigurableParent(target);
} }
return new ApplicationConditionEvaluation(contextConditionEvaluations); return new ApplicationConditionEvaluation(contextConditionEvaluations);
} }
private ConfigurableApplicationContext getConfigurableParent( private ConfigurableApplicationContext getConfigurableParent(ConfigurableApplicationContext context) {
ConfigurableApplicationContext context) {
ApplicationContext parent = context.getParent(); ApplicationContext parent = context.getParent();
if (parent instanceof ConfigurableApplicationContext) { if (parent instanceof ConfigurableApplicationContext) {
return (ConfigurableApplicationContext) parent; return (ConfigurableApplicationContext) parent;
@ -88,8 +86,7 @@ public class ConditionsReportEndpoint {
private final Map<String, ContextConditionEvaluation> contexts; private final Map<String, ContextConditionEvaluation> contexts;
private ApplicationConditionEvaluation( private ApplicationConditionEvaluation(Map<String, ContextConditionEvaluation> contexts) {
Map<String, ContextConditionEvaluation> contexts) {
this.contexts = contexts; this.contexts = contexts;
} }
@ -117,27 +114,24 @@ public class ConditionsReportEndpoint {
private final String parentId; private final String parentId;
public ContextConditionEvaluation(ConfigurableApplicationContext context) { public ContextConditionEvaluation(ConfigurableApplicationContext context) {
ConditionEvaluationReport report = ConditionEvaluationReport ConditionEvaluationReport report = ConditionEvaluationReport.get(context.getBeanFactory());
.get(context.getBeanFactory());
this.positiveMatches = new LinkedMultiValueMap<>(); this.positiveMatches = new LinkedMultiValueMap<>();
this.negativeMatches = new LinkedHashMap<>(); this.negativeMatches = new LinkedHashMap<>();
this.exclusions = report.getExclusions(); this.exclusions = report.getExclusions();
this.unconditionalClasses = report.getUnconditionalClasses(); this.unconditionalClasses = report.getUnconditionalClasses();
report.getConditionAndOutcomesBySource().forEach( report.getConditionAndOutcomesBySource()
(source, conditionAndOutcomes) -> add(source, conditionAndOutcomes)); .forEach((source, conditionAndOutcomes) -> add(source, conditionAndOutcomes));
this.parentId = (context.getParent() != null) ? context.getParent().getId() this.parentId = (context.getParent() != null) ? context.getParent().getId() : null;
: null;
} }
private void add(String source, ConditionAndOutcomes conditionAndOutcomes) { private void add(String source, ConditionAndOutcomes conditionAndOutcomes) {
String name = ClassUtils.getShortName(source); String name = ClassUtils.getShortName(source);
if (conditionAndOutcomes.isFullMatch()) { if (conditionAndOutcomes.isFullMatch()) {
conditionAndOutcomes.forEach((conditionAndOutcome) -> this.positiveMatches conditionAndOutcomes.forEach((conditionAndOutcome) -> this.positiveMatches.add(name,
.add(name, new MessageAndCondition(conditionAndOutcome))); new MessageAndCondition(conditionAndOutcome)));
} }
else { else {
this.negativeMatches.put(name, this.negativeMatches.put(name, new MessageAndConditions(conditionAndOutcomes));
new MessageAndConditions(conditionAndOutcomes));
} }
} }
@ -175,8 +169,8 @@ public class ConditionsReportEndpoint {
public MessageAndConditions(ConditionAndOutcomes conditionAndOutcomes) { public MessageAndConditions(ConditionAndOutcomes conditionAndOutcomes) {
for (ConditionAndOutcome conditionAndOutcome : conditionAndOutcomes) { for (ConditionAndOutcome conditionAndOutcome : conditionAndOutcomes) {
List<MessageAndCondition> target = (conditionAndOutcome.getOutcome() List<MessageAndCondition> target = (conditionAndOutcome.getOutcome().isMatch() ? this.matched
.isMatch() ? this.matched : this.notMatched); : this.notMatched);
target.add(new MessageAndCondition(conditionAndOutcome)); target.add(new MessageAndCondition(conditionAndOutcome));
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -37,8 +37,7 @@ public class ConditionsReportEndpointAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean(search = SearchStrategy.CURRENT) @ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
@ConditionalOnEnabledEndpoint @ConditionalOnEnabledEndpoint
public ConditionsReportEndpoint conditionsReportEndpoint( public ConditionsReportEndpoint conditionsReportEndpoint(ConfigurableApplicationContext context) {
ConfigurableApplicationContext context) {
return new ConditionsReportEndpoint(context); return new ConditionsReportEndpoint(context);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -59,8 +59,8 @@ public class ElasticsearchHealthIndicatorAutoConfiguration {
@ConditionalOnClass(Client.class) @ConditionalOnClass(Client.class)
@ConditionalOnBean(Client.class) @ConditionalOnBean(Client.class)
@EnableConfigurationProperties(ElasticsearchHealthIndicatorProperties.class) @EnableConfigurationProperties(ElasticsearchHealthIndicatorProperties.class)
static class ElasticsearchClientHealthIndicatorConfiguration extends static class ElasticsearchClientHealthIndicatorConfiguration
CompositeHealthIndicatorConfiguration<ElasticsearchHealthIndicator, Client> { extends CompositeHealthIndicatorConfiguration<ElasticsearchHealthIndicator, Client> {
private final Map<String, Client> clients; private final Map<String, Client> clients;
@ -82,8 +82,7 @@ public class ElasticsearchHealthIndicatorAutoConfiguration {
protected ElasticsearchHealthIndicator createHealthIndicator(Client client) { protected ElasticsearchHealthIndicator createHealthIndicator(Client client) {
Duration responseTimeout = this.properties.getResponseTimeout(); Duration responseTimeout = this.properties.getResponseTimeout();
return new ElasticsearchHealthIndicator(client, return new ElasticsearchHealthIndicator(client,
(responseTimeout != null) ? responseTimeout.toMillis() : 100, (responseTimeout != null) ? responseTimeout.toMillis() : 100, this.properties.getIndices());
this.properties.getIndices());
} }
} }
@ -91,8 +90,8 @@ public class ElasticsearchHealthIndicatorAutoConfiguration {
@Configuration @Configuration
@ConditionalOnClass(JestClient.class) @ConditionalOnClass(JestClient.class)
@ConditionalOnBean(JestClient.class) @ConditionalOnBean(JestClient.class)
static class ElasticsearchJestHealthIndicatorConfiguration extends static class ElasticsearchJestHealthIndicatorConfiguration
CompositeHealthIndicatorConfiguration<ElasticsearchJestHealthIndicator, JestClient> { extends CompositeHealthIndicatorConfiguration<ElasticsearchJestHealthIndicator, JestClient> {
private final Map<String, JestClient> clients; private final Map<String, JestClient> clients;
@ -107,8 +106,7 @@ public class ElasticsearchHealthIndicatorAutoConfiguration {
} }
@Override @Override
protected ElasticsearchJestHealthIndicator createHealthIndicator( protected ElasticsearchJestHealthIndicator createHealthIndicator(JestClient client) {
JestClient client) {
return new ElasticsearchJestHealthIndicator(client); return new ElasticsearchJestHealthIndicator(client);
} }

@ -30,8 +30,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
* @author Andy Wilkinson * @author Andy Wilkinson
* @since 2.0.0 * @since 2.0.0
*/ */
@ConfigurationProperties(prefix = "management.health.elasticsearch", @ConfigurationProperties(prefix = "management.health.elasticsearch", ignoreUnknownFields = false)
ignoreUnknownFields = false)
public class ElasticsearchHealthIndicatorProperties { public class ElasticsearchHealthIndicatorProperties {
/** /**

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -44,10 +44,8 @@ public class EndpointAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public CachingOperationInvokerAdvisor endpointCachingOperationInvokerAdvisor( public CachingOperationInvokerAdvisor endpointCachingOperationInvokerAdvisor(Environment environment) {
Environment environment) { return new CachingOperationInvokerAdvisor(new EndpointIdTimeToLivePropertyFunction(environment));
return new CachingOperationInvokerAdvisor(
new EndpointIdTimeToLivePropertyFunction(environment));
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -50,8 +50,7 @@ class EndpointIdTimeToLivePropertyFunction implements Function<EndpointId, Long>
@Override @Override
public Long apply(EndpointId 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.toLowerCaseString());
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);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -42,8 +42,7 @@ import org.springframework.util.Assert;
* @author Phillip Webb * @author Phillip Webb
* @since 2.0.0 * @since 2.0.0
*/ */
public class ExposeExcludePropertyEndpointFilter<E extends ExposableEndpoint<?>> public class ExposeExcludePropertyEndpointFilter<E extends ExposableEndpoint<?>> implements EndpointFilter<E> {
implements EndpointFilter<E> {
private final Class<E> endpointType; private final Class<E> endpointType;
@ -53,8 +52,8 @@ public class ExposeExcludePropertyEndpointFilter<E extends ExposableEndpoint<?>>
private final Set<String> exposeDefaults; private final Set<String> exposeDefaults;
public ExposeExcludePropertyEndpointFilter(Class<E> endpointType, public ExposeExcludePropertyEndpointFilter(Class<E> endpointType, Environment environment, String prefix,
Environment environment, String prefix, String... exposeDefaults) { String... exposeDefaults) {
Assert.notNull(endpointType, "EndpointType must not be null"); Assert.notNull(endpointType, "EndpointType must not be null");
Assert.notNull(environment, "Environment must not be null"); Assert.notNull(environment, "Environment must not be null");
Assert.hasText(prefix, "Prefix must not be empty"); Assert.hasText(prefix, "Prefix must not be empty");
@ -65,9 +64,8 @@ public class ExposeExcludePropertyEndpointFilter<E extends ExposableEndpoint<?>>
this.exposeDefaults = asSet(Arrays.asList(exposeDefaults)); this.exposeDefaults = asSet(Arrays.asList(exposeDefaults));
} }
public ExposeExcludePropertyEndpointFilter(Class<E> endpointType, public ExposeExcludePropertyEndpointFilter(Class<E> endpointType, Collection<String> include,
Collection<String> include, Collection<String> exclude, Collection<String> exclude, String... exposeDefaults) {
String... exposeDefaults) {
Assert.notNull(endpointType, "EndpointType Type must not be null"); Assert.notNull(endpointType, "EndpointType Type must not be null");
this.endpointType = endpointType; this.endpointType = endpointType;
this.include = asSet(include); this.include = asSet(include);
@ -76,8 +74,7 @@ public class ExposeExcludePropertyEndpointFilter<E extends ExposableEndpoint<?>>
} }
private Set<String> bind(Binder binder, String name) { private Set<String> bind(Binder binder, String name) {
return asSet(binder.bind(name, Bindable.listOf(String.class)).map(this::cleanup) return asSet(binder.bind(name, Bindable.listOf(String.class)).map(this::cleanup).orElseGet(ArrayList::new));
.orElseGet(ArrayList::new));
} }
private List<String> cleanup(List<String> values) { private List<String> cleanup(List<String> values) {
@ -85,8 +82,7 @@ public class ExposeExcludePropertyEndpointFilter<E extends ExposableEndpoint<?>>
} }
private String cleanup(String value) { private String cleanup(String value) {
return "*".equals(value) ? "*" return "*".equals(value) ? "*" : EndpointId.fromPropertyValue(value).toLowerCaseString();
: EndpointId.fromPropertyValue(value).toLowerCaseString();
} }
private Set<String> asSet(Collection<String> items) { private Set<String> asSet(Collection<String> items) {
@ -107,8 +103,7 @@ public class ExposeExcludePropertyEndpointFilter<E extends ExposableEndpoint<?>>
private boolean isExposed(ExposableEndpoint<?> endpoint) { private boolean isExposed(ExposableEndpoint<?> endpoint) {
if (this.include.isEmpty()) { if (this.include.isEmpty()) {
return this.exposeDefaults.contains("*") return this.exposeDefaults.contains("*") || contains(this.exposeDefaults, endpoint);
|| contains(this.exposeDefaults, endpoint);
} }
return this.include.contains("*") || contains(this.include, endpoint); return this.include.contains("*") || contains(this.include, endpoint);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -51,8 +51,7 @@ class OnEnabledEndpointCondition extends SpringBootCondition {
private static final ConcurrentReferenceHashMap<Environment, Optional<Boolean>> enabledByDefaultCache = new ConcurrentReferenceHashMap<>(); private static final ConcurrentReferenceHashMap<Environment, Optional<Boolean>> enabledByDefaultCache = new ConcurrentReferenceHashMap<>();
@Override @Override
public ConditionOutcome getMatchOutcome(ConditionContext context, public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment(); Environment environment = context.getEnvironment();
AnnotationAttributes attributes = getEndpointAttributes(context, metadata); AnnotationAttributes attributes = getEndpointAttributes(context, metadata);
EndpointId id = EndpointId.of(attributes.getString("id")); EndpointId id = EndpointId.of(attributes.getString("id"));
@ -61,46 +60,37 @@ class OnEnabledEndpointCondition extends SpringBootCondition {
if (userDefinedEnabled != null) { if (userDefinedEnabled != null) {
return new ConditionOutcome(userDefinedEnabled, return new ConditionOutcome(userDefinedEnabled,
ConditionMessage.forCondition(ConditionalOnEnabledEndpoint.class) ConditionMessage.forCondition(ConditionalOnEnabledEndpoint.class)
.because("found property " + key + " with value " .because("found property " + key + " with value " + userDefinedEnabled));
+ userDefinedEnabled));
} }
Boolean userDefinedDefault = isEnabledByDefault(environment); Boolean userDefinedDefault = isEnabledByDefault(environment);
if (userDefinedDefault != null) { if (userDefinedDefault != null) {
return new ConditionOutcome(userDefinedDefault, return new ConditionOutcome(userDefinedDefault,
ConditionMessage.forCondition(ConditionalOnEnabledEndpoint.class) ConditionMessage.forCondition(ConditionalOnEnabledEndpoint.class).because("no property " + key
.because("no property " + key + " found so using user defined default from " + ENABLED_BY_DEFAULT_KEY));
+ " found so using user defined default from "
+ ENABLED_BY_DEFAULT_KEY));
} }
boolean endpointDefault = attributes.getBoolean("enableByDefault"); boolean endpointDefault = attributes.getBoolean("enableByDefault");
return new ConditionOutcome(endpointDefault, return new ConditionOutcome(endpointDefault, ConditionMessage.forCondition(ConditionalOnEnabledEndpoint.class)
ConditionMessage.forCondition(ConditionalOnEnabledEndpoint.class).because( .because("no property " + key + " found so using endpoint default"));
"no property " + key + " found so using endpoint default"));
} }
private Boolean isEnabledByDefault(Environment environment) { private Boolean isEnabledByDefault(Environment environment) {
Optional<Boolean> enabledByDefault = enabledByDefaultCache.get(environment); Optional<Boolean> enabledByDefault = enabledByDefaultCache.get(environment);
if (enabledByDefault == null) { if (enabledByDefault == null) {
enabledByDefault = Optional.ofNullable( enabledByDefault = Optional.ofNullable(environment.getProperty(ENABLED_BY_DEFAULT_KEY, Boolean.class));
environment.getProperty(ENABLED_BY_DEFAULT_KEY, Boolean.class));
enabledByDefaultCache.put(environment, enabledByDefault); enabledByDefaultCache.put(environment, enabledByDefault);
} }
return enabledByDefault.orElse(null); return enabledByDefault.orElse(null);
} }
private AnnotationAttributes getEndpointAttributes(ConditionContext context, private AnnotationAttributes getEndpointAttributes(ConditionContext context, AnnotatedTypeMetadata metadata) {
AnnotatedTypeMetadata metadata) { Assert.state(metadata instanceof MethodMetadata && metadata.isAnnotated(Bean.class.getName()),
Assert.state(
metadata instanceof MethodMetadata
&& metadata.isAnnotated(Bean.class.getName()),
"OnEnabledEndpointCondition may only be used on @Bean methods"); "OnEnabledEndpointCondition may only be used on @Bean methods");
Class<?> endpointType = getEndpointType(context, (MethodMetadata) metadata); Class<?> endpointType = getEndpointType(context, (MethodMetadata) metadata);
return getEndpointAttributes(endpointType); return getEndpointAttributes(endpointType);
} }
private Class<?> getEndpointType(ConditionContext context, MethodMetadata metadata) { private Class<?> getEndpointType(ConditionContext context, MethodMetadata metadata) {
Map<String, Object> attributes = metadata Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnEnabledEndpoint.class.getName());
.getAnnotationAttributes(ConditionalOnEnabledEndpoint.class.getName());
if (attributes != null && attributes.containsKey("endpoint")) { if (attributes != null && attributes.containsKey("endpoint")) {
Class<?> target = (Class<?>) attributes.get("endpoint"); Class<?> target = (Class<?>) attributes.get("endpoint");
if (target != Void.class) { if (target != Void.class) {
@ -109,26 +99,22 @@ class OnEnabledEndpointCondition extends SpringBootCondition {
} }
// We should be safe to load at this point since we are in the REGISTER_BEAN phase // We should be safe to load at this point since we are in the REGISTER_BEAN phase
try { try {
return ClassUtils.forName(metadata.getReturnTypeName(), return ClassUtils.forName(metadata.getReturnTypeName(), context.getClassLoader());
context.getClassLoader());
} }
catch (Throwable ex) { catch (Throwable ex) {
throw new IllegalStateException("Failed to extract endpoint id for " throw new IllegalStateException("Failed to extract endpoint id for " + metadata.getDeclaringClassName()
+ metadata.getDeclaringClassName() + "." + metadata.getMethodName(), + "." + metadata.getMethodName(), ex);
ex);
} }
} }
protected AnnotationAttributes getEndpointAttributes(Class<?> type) { protected AnnotationAttributes getEndpointAttributes(Class<?> type) {
AnnotationAttributes attributes = AnnotatedElementUtils AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(type, Endpoint.class,
.findMergedAnnotationAttributes(type, Endpoint.class, true, true); true, true);
if (attributes != null) { if (attributes != null) {
return attributes; return attributes;
} }
attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(type, attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(type, EndpointExtension.class, false, true);
EndpointExtension.class, false, true); Assert.state(attributes != null, "No endpoint is specified and the return type of the @Bean method is "
Assert.state(attributes != null,
"No endpoint is specified and the return type of the @Bean method is "
+ "neither an @Endpoint, nor an @EndpointExtension"); + "neither an @Endpoint, nor an @EndpointExtension");
return getEndpointAttributes(attributes.getClass("endpoint")); return getEndpointAttributes(attributes.getClass("endpoint"));
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -40,20 +40,17 @@ class DefaultEndpointObjectNameFactory implements EndpointObjectNameFactory {
private final String contextId; private final String contextId;
DefaultEndpointObjectNameFactory(JmxEndpointProperties properties, DefaultEndpointObjectNameFactory(JmxEndpointProperties properties, MBeanServer mBeanServer, String contextId) {
MBeanServer mBeanServer, String contextId) {
this.properties = properties; this.properties = properties;
this.mBeanServer = mBeanServer; this.mBeanServer = mBeanServer;
this.contextId = contextId; this.contextId = contextId;
} }
@Override @Override
public ObjectName getObjectName(ExposableJmxEndpoint endpoint) public ObjectName getObjectName(ExposableJmxEndpoint endpoint) throws MalformedObjectNameException {
throws MalformedObjectNameException {
StringBuilder builder = new StringBuilder(this.properties.getDomain()); StringBuilder builder = new StringBuilder(this.properties.getDomain());
builder.append(":type=Endpoint"); builder.append(":type=Endpoint");
builder.append( builder.append(",name=" + StringUtils.capitalize(endpoint.getEndpointId().toString()));
",name=" + StringUtils.capitalize(endpoint.getEndpointId().toString()));
String baseName = builder.toString(); String baseName = builder.toString();
if (this.mBeanServer != null && hasMBean(baseName)) { if (this.mBeanServer != null && hasMBean(baseName)) {
builder.append(",context=" + this.contextId); builder.append(",context=" + this.contextId);
@ -76,8 +73,7 @@ class DefaultEndpointObjectNameFactory implements EndpointObjectNameFactory {
return ""; return "";
} }
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
this.properties.getStaticNames() this.properties.getStaticNames().forEach((name, value) -> builder.append("," + name + "=" + value));
.forEach((name, value) -> builder.append("," + name + "=" + value));
return builder.toString(); return builder.toString();
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -64,31 +64,27 @@ public class JmxEndpointAutoConfiguration {
private final JmxEndpointProperties properties; private final JmxEndpointProperties properties;
public JmxEndpointAutoConfiguration(ApplicationContext applicationContext, public JmxEndpointAutoConfiguration(ApplicationContext applicationContext, JmxEndpointProperties properties) {
JmxEndpointProperties properties) {
this.applicationContext = applicationContext; this.applicationContext = applicationContext;
this.properties = properties; this.properties = properties;
} }
@Bean @Bean
@ConditionalOnMissingBean(JmxEndpointsSupplier.class) @ConditionalOnMissingBean(JmxEndpointsSupplier.class)
public JmxEndpointDiscoverer jmxAnnotationEndpointDiscoverer( public JmxEndpointDiscoverer jmxAnnotationEndpointDiscoverer(ParameterValueMapper parameterValueMapper,
ParameterValueMapper parameterValueMapper,
ObjectProvider<Collection<OperationInvokerAdvisor>> invokerAdvisors, ObjectProvider<Collection<OperationInvokerAdvisor>> invokerAdvisors,
ObjectProvider<Collection<EndpointFilter<ExposableJmxEndpoint>>> filters) { ObjectProvider<Collection<EndpointFilter<ExposableJmxEndpoint>>> filters) {
return new JmxEndpointDiscoverer(this.applicationContext, parameterValueMapper, return new JmxEndpointDiscoverer(this.applicationContext, parameterValueMapper,
invokerAdvisors.getIfAvailable(Collections::emptyList), invokerAdvisors.getIfAvailable(Collections::emptyList), filters.getIfAvailable(Collections::emptyList));
filters.getIfAvailable(Collections::emptyList));
} }
@Bean @Bean
@ConditionalOnSingleCandidate(MBeanServer.class) @ConditionalOnSingleCandidate(MBeanServer.class)
public JmxEndpointExporter jmxMBeanExporter(MBeanServer mBeanServer, public JmxEndpointExporter jmxMBeanExporter(MBeanServer mBeanServer, ObjectProvider<ObjectMapper> objectMapper,
ObjectProvider<ObjectMapper> objectMapper,
JmxEndpointsSupplier jmxEndpointsSupplier) { JmxEndpointsSupplier jmxEndpointsSupplier) {
String contextId = ObjectUtils.getIdentityHexString(this.applicationContext); String contextId = ObjectUtils.getIdentityHexString(this.applicationContext);
EndpointObjectNameFactory objectNameFactory = new DefaultEndpointObjectNameFactory( EndpointObjectNameFactory objectNameFactory = new DefaultEndpointObjectNameFactory(this.properties, mBeanServer,
this.properties, mBeanServer, contextId); contextId);
JmxOperationResponseMapper responseMapper = new JacksonJmxOperationResponseMapper( JmxOperationResponseMapper responseMapper = new JacksonJmxOperationResponseMapper(
objectMapper.getIfAvailable()); objectMapper.getIfAvailable());
return new JmxEndpointExporter(mBeanServer, objectNameFactory, responseMapper, return new JmxEndpointExporter(mBeanServer, objectNameFactory, responseMapper,
@ -99,8 +95,8 @@ public class JmxEndpointAutoConfiguration {
@Bean @Bean
public ExposeExcludePropertyEndpointFilter<ExposableJmxEndpoint> jmxIncludeExcludePropertyEndpointFilter() { public ExposeExcludePropertyEndpointFilter<ExposableJmxEndpoint> jmxIncludeExcludePropertyEndpointFilter() {
JmxEndpointProperties.Exposure exposure = this.properties.getExposure(); JmxEndpointProperties.Exposure exposure = this.properties.getExposure();
return new ExposeExcludePropertyEndpointFilter<>(ExposableJmxEndpoint.class, return new ExposeExcludePropertyEndpointFilter<>(ExposableJmxEndpoint.class, exposure.getInclude(),
exposure.getInclude(), exposure.getExclude(), "*"); exposure.getExclude(), "*");
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -125,16 +125,11 @@ public class CorsEndpointProperties {
PropertyMapper map = PropertyMapper.get(); PropertyMapper map = PropertyMapper.get();
CorsConfiguration configuration = new CorsConfiguration(); CorsConfiguration configuration = new CorsConfiguration();
map.from(this::getAllowedOrigins).to(configuration::setAllowedOrigins); map.from(this::getAllowedOrigins).to(configuration::setAllowedOrigins);
map.from(this::getAllowedHeaders).whenNot(CollectionUtils::isEmpty) map.from(this::getAllowedHeaders).whenNot(CollectionUtils::isEmpty).to(configuration::setAllowedHeaders);
.to(configuration::setAllowedHeaders); map.from(this::getAllowedMethods).whenNot(CollectionUtils::isEmpty).to(configuration::setAllowedMethods);
map.from(this::getAllowedMethods).whenNot(CollectionUtils::isEmpty) map.from(this::getExposedHeaders).whenNot(CollectionUtils::isEmpty).to(configuration::setExposedHeaders);
.to(configuration::setAllowedMethods); map.from(this::getMaxAge).whenNonNull().as(Duration::getSeconds).to(configuration::setMaxAge);
map.from(this::getExposedHeaders).whenNot(CollectionUtils::isEmpty) map.from(this::getAllowCredentials).whenNonNull().to(configuration::setAllowCredentials);
.to(configuration::setExposedHeaders);
map.from(this::getMaxAge).whenNonNull().as(Duration::getSeconds)
.to(configuration::setMaxAge);
map.from(this::getAllowCredentials).whenNonNull()
.to(configuration::setAllowCredentials);
return configuration; return configuration;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -35,8 +35,7 @@ class MappingWebEndpointPathMapper implements PathMapper {
MappingWebEndpointPathMapper(Map<String, String> pathMapping) { MappingWebEndpointPathMapper(Map<String, String> pathMapping) {
this.pathMapping = new HashMap<>(); this.pathMapping = new HashMap<>();
pathMapping.forEach((id, path) -> this.pathMapping pathMapping.forEach((id, path) -> this.pathMapping.put(EndpointId.fromPropertyValue(id), path));
.put(EndpointId.fromPropertyValue(id), path));
} }
@Override @Override
@ -48,8 +47,7 @@ class MappingWebEndpointPathMapper implements PathMapper {
@Override @Override
public String getRootPath(EndpointId endpointId) { public String getRootPath(EndpointId endpointId) {
String path = this.pathMapping.get(endpointId); String path = this.pathMapping.get(endpointId);
return StringUtils.hasText(path) ? path return StringUtils.hasText(path) ? path : PathMapper.useEndpointId().getRootPath(endpointId);
: PathMapper.useEndpointId().getRootPath(endpointId);
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -50,8 +50,8 @@ public class ServletEndpointManagementContextConfiguration {
public ExposeExcludePropertyEndpointFilter<ExposableServletEndpoint> servletExposeExcludePropertyEndpointFilter( public ExposeExcludePropertyEndpointFilter<ExposableServletEndpoint> servletExposeExcludePropertyEndpointFilter(
WebEndpointProperties properties) { WebEndpointProperties properties) {
WebEndpointProperties.Exposure exposure = properties.getExposure(); WebEndpointProperties.Exposure exposure = properties.getExposure();
return new ExposeExcludePropertyEndpointFilter<>(ExposableServletEndpoint.class, return new ExposeExcludePropertyEndpointFilter<>(ExposableServletEndpoint.class, exposure.getInclude(),
exposure.getInclude(), exposure.getExclude()); exposure.getExclude());
} }
@Configuration @Configuration
@ -60,19 +60,15 @@ public class ServletEndpointManagementContextConfiguration {
private final ApplicationContext context; private final ApplicationContext context;
public WebMvcServletEndpointManagementContextConfiguration( public WebMvcServletEndpointManagementContextConfiguration(ApplicationContext context) {
ApplicationContext context) {
this.context = context; this.context = context;
} }
@Bean @Bean
public ServletEndpointRegistrar servletEndpointRegistrar( public ServletEndpointRegistrar servletEndpointRegistrar(WebEndpointProperties properties,
WebEndpointProperties properties,
ServletEndpointsSupplier servletEndpointsSupplier) { ServletEndpointsSupplier servletEndpointsSupplier) {
DispatcherServletPath dispatcherServletPath = this.context DispatcherServletPath dispatcherServletPath = this.context.getBean(DispatcherServletPath.class);
.getBean(DispatcherServletPath.class); return new ServletEndpointRegistrar(dispatcherServletPath.getRelativePath(properties.getBasePath()),
return new ServletEndpointRegistrar(
dispatcherServletPath.getRelativePath(properties.getBasePath()),
servletEndpointsSupplier.getEndpoints()); servletEndpointsSupplier.getEndpoints());
} }
@ -85,19 +81,15 @@ public class ServletEndpointManagementContextConfiguration {
private final ApplicationContext context; private final ApplicationContext context;
public JerseyServletEndpointManagementContextConfiguration( public JerseyServletEndpointManagementContextConfiguration(ApplicationContext context) {
ApplicationContext context) {
this.context = context; this.context = context;
} }
@Bean @Bean
public ServletEndpointRegistrar servletEndpointRegistrar( public ServletEndpointRegistrar servletEndpointRegistrar(WebEndpointProperties properties,
WebEndpointProperties properties,
ServletEndpointsSupplier servletEndpointsSupplier) { ServletEndpointsSupplier servletEndpointsSupplier) {
JerseyApplicationPath jerseyApplicationPath = this.context JerseyApplicationPath jerseyApplicationPath = this.context.getBean(JerseyApplicationPath.class);
.getBean(JerseyApplicationPath.class); return new ServletEndpointRegistrar(jerseyApplicationPath.getRelativePath(properties.getBasePath()),
return new ServletEndpointRegistrar(
jerseyApplicationPath.getRelativePath(properties.getBasePath()),
servletEndpointsSupplier.getEndpoints()); servletEndpointsSupplier.getEndpoints());
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -65,15 +65,13 @@ import org.springframework.context.annotation.Configuration;
@EnableConfigurationProperties(WebEndpointProperties.class) @EnableConfigurationProperties(WebEndpointProperties.class)
public class WebEndpointAutoConfiguration { public class WebEndpointAutoConfiguration {
private static final List<String> MEDIA_TYPES = Arrays private static final List<String> MEDIA_TYPES = Arrays.asList(ActuatorMediaType.V2_JSON, "application/json");
.asList(ActuatorMediaType.V2_JSON, "application/json");
private final ApplicationContext applicationContext; private final ApplicationContext applicationContext;
private final WebEndpointProperties properties; private final WebEndpointProperties properties;
public WebEndpointAutoConfiguration(ApplicationContext applicationContext, public WebEndpointAutoConfiguration(ApplicationContext applicationContext, WebEndpointProperties properties) {
WebEndpointProperties properties) {
this.applicationContext = applicationContext; this.applicationContext = applicationContext;
this.properties = properties; this.properties = properties;
} }
@ -92,47 +90,41 @@ public class WebEndpointAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean(WebEndpointsSupplier.class) @ConditionalOnMissingBean(WebEndpointsSupplier.class)
public WebEndpointDiscoverer webEndpointDiscoverer( public WebEndpointDiscoverer webEndpointDiscoverer(ParameterValueMapper parameterValueMapper,
ParameterValueMapper parameterValueMapper,
EndpointMediaTypes endpointMediaTypes, PathMapper webEndpointPathMapper, EndpointMediaTypes endpointMediaTypes, PathMapper webEndpointPathMapper,
ObjectProvider<Collection<OperationInvokerAdvisor>> invokerAdvisors, ObjectProvider<Collection<OperationInvokerAdvisor>> invokerAdvisors,
ObjectProvider<Collection<EndpointFilter<ExposableWebEndpoint>>> filters) { ObjectProvider<Collection<EndpointFilter<ExposableWebEndpoint>>> filters) {
return new WebEndpointDiscoverer(this.applicationContext, parameterValueMapper, return new WebEndpointDiscoverer(this.applicationContext, parameterValueMapper, endpointMediaTypes,
endpointMediaTypes, webEndpointPathMapper, webEndpointPathMapper, invokerAdvisors.getIfAvailable(Collections::emptyList),
invokerAdvisors.getIfAvailable(Collections::emptyList),
filters.getIfAvailable(Collections::emptyList)); filters.getIfAvailable(Collections::emptyList));
} }
@Bean @Bean
@ConditionalOnMissingBean(ControllerEndpointsSupplier.class) @ConditionalOnMissingBean(ControllerEndpointsSupplier.class)
public ControllerEndpointDiscoverer controllerEndpointDiscoverer( public ControllerEndpointDiscoverer controllerEndpointDiscoverer(PathMapper webEndpointPathMapper,
PathMapper webEndpointPathMapper,
ObjectProvider<Collection<EndpointFilter<ExposableControllerEndpoint>>> filters) { ObjectProvider<Collection<EndpointFilter<ExposableControllerEndpoint>>> filters) {
return new ControllerEndpointDiscoverer(this.applicationContext, return new ControllerEndpointDiscoverer(this.applicationContext, webEndpointPathMapper,
webEndpointPathMapper, filters.getIfAvailable(Collections::emptyList)); filters.getIfAvailable(Collections::emptyList));
} }
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public PathMappedEndpoints pathMappedEndpoints( public PathMappedEndpoints pathMappedEndpoints(Collection<EndpointsSupplier<?>> endpointSuppliers,
Collection<EndpointsSupplier<?>> endpointSuppliers,
WebEndpointProperties webEndpointProperties) { WebEndpointProperties webEndpointProperties) {
return new PathMappedEndpoints(webEndpointProperties.getBasePath(), return new PathMappedEndpoints(webEndpointProperties.getBasePath(), endpointSuppliers);
endpointSuppliers);
} }
@Bean @Bean
public ExposeExcludePropertyEndpointFilter<ExposableWebEndpoint> webExposeExcludePropertyEndpointFilter() { public ExposeExcludePropertyEndpointFilter<ExposableWebEndpoint> webExposeExcludePropertyEndpointFilter() {
WebEndpointProperties.Exposure exposure = this.properties.getExposure(); WebEndpointProperties.Exposure exposure = this.properties.getExposure();
return new ExposeExcludePropertyEndpointFilter<>(ExposableWebEndpoint.class, return new ExposeExcludePropertyEndpointFilter<>(ExposableWebEndpoint.class, exposure.getInclude(),
exposure.getInclude(), exposure.getExclude(), "info", "health"); exposure.getExclude(), "info", "health");
} }
@Bean @Bean
public ExposeExcludePropertyEndpointFilter<ExposableControllerEndpoint> controllerExposeExcludePropertyEndpointFilter() { public ExposeExcludePropertyEndpointFilter<ExposableControllerEndpoint> controllerExposeExcludePropertyEndpointFilter() {
WebEndpointProperties.Exposure exposure = this.properties.getExposure(); WebEndpointProperties.Exposure exposure = this.properties.getExposure();
return new ExposeExcludePropertyEndpointFilter<>( return new ExposeExcludePropertyEndpointFilter<>(ExposableControllerEndpoint.class, exposure.getInclude(),
ExposableControllerEndpoint.class, exposure.getInclude(),
exposure.getExclude()); exposure.getExclude());
} }
@ -142,11 +134,10 @@ public class WebEndpointAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean(ServletEndpointsSupplier.class) @ConditionalOnMissingBean(ServletEndpointsSupplier.class)
public ServletEndpointDiscoverer servletEndpointDiscoverer( public ServletEndpointDiscoverer servletEndpointDiscoverer(ApplicationContext applicationContext,
ApplicationContext applicationContext, PathMapper webEndpointPathMapper, PathMapper webEndpointPathMapper,
ObjectProvider<Collection<EndpointFilter<ExposableServletEndpoint>>> filters) { ObjectProvider<Collection<EndpointFilter<ExposableServletEndpoint>>> filters) {
return new ServletEndpointDiscoverer(applicationContext, return new ServletEndpointDiscoverer(applicationContext, webEndpointPathMapper,
webEndpointPathMapper,
filters.getIfAvailable(Collections::emptyList)); filters.getIfAvailable(Collections::emptyList));
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -57,8 +57,7 @@ public class WebEndpointProperties {
} }
public void setBasePath(String basePath) { public void setBasePath(String basePath) {
Assert.isTrue(basePath.isEmpty() || basePath.startsWith("/"), Assert.isTrue(basePath.isEmpty() || basePath.startsWith("/"), "Base path must start with '/' or be empty");
"Base path must start with '/' or be empty");
this.basePath = cleanBasePath(basePath); this.basePath = cleanBasePath(basePath);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -57,10 +57,8 @@ import org.springframework.context.annotation.Bean;
class JerseyWebEndpointManagementContextConfiguration { class JerseyWebEndpointManagementContextConfiguration {
@Bean @Bean
public ResourceConfigCustomizer webEndpointRegistrar( public ResourceConfigCustomizer webEndpointRegistrar(WebEndpointsSupplier webEndpointsSupplier,
WebEndpointsSupplier webEndpointsSupplier, ServletEndpointsSupplier servletEndpointsSupplier, EndpointMediaTypes endpointMediaTypes,
ServletEndpointsSupplier servletEndpointsSupplier,
EndpointMediaTypes endpointMediaTypes,
WebEndpointProperties webEndpointProperties) { WebEndpointProperties webEndpointProperties) {
List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>(); List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
allEndpoints.addAll(webEndpointsSupplier.getEndpoints()); allEndpoints.addAll(webEndpointsSupplier.getEndpoints());
@ -71,10 +69,8 @@ class JerseyWebEndpointManagementContextConfiguration {
EndpointMapping endpointMapping = new EndpointMapping(basePath); EndpointMapping endpointMapping = new EndpointMapping(basePath);
Collection<ExposableWebEndpoint> webEndpoints = Collections Collection<ExposableWebEndpoint> webEndpoints = Collections
.unmodifiableCollection(webEndpointsSupplier.getEndpoints()); .unmodifiableCollection(webEndpointsSupplier.getEndpoints());
resourceConfig.registerResources( resourceConfig.registerResources(new HashSet<>(resourceFactory.createEndpointResources(endpointMapping,
new HashSet<>(resourceFactory.createEndpointResources(endpointMapping, webEndpoints, endpointMediaTypes, new EndpointLinksResolver(allEndpoints, basePath))));
webEndpoints, endpointMediaTypes,
new EndpointLinksResolver(allEndpoints, basePath))));
}; };
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -59,33 +59,26 @@ public class WebFluxEndpointManagementContextConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public WebFluxEndpointHandlerMapping webEndpointReactiveHandlerMapping( public WebFluxEndpointHandlerMapping webEndpointReactiveHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,
WebEndpointsSupplier webEndpointsSupplier, ControllerEndpointsSupplier controllerEndpointsSupplier, EndpointMediaTypes endpointMediaTypes,
ControllerEndpointsSupplier controllerEndpointsSupplier, CorsEndpointProperties corsProperties, WebEndpointProperties webEndpointProperties) {
EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties, EndpointMapping endpointMapping = new EndpointMapping(webEndpointProperties.getBasePath());
WebEndpointProperties webEndpointProperties) {
EndpointMapping endpointMapping = new EndpointMapping(
webEndpointProperties.getBasePath());
Collection<ExposableWebEndpoint> endpoints = webEndpointsSupplier.getEndpoints(); Collection<ExposableWebEndpoint> endpoints = webEndpointsSupplier.getEndpoints();
List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>(); List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
allEndpoints.addAll(endpoints); allEndpoints.addAll(endpoints);
allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints()); allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
return new WebFluxEndpointHandlerMapping(endpointMapping, endpoints, return new WebFluxEndpointHandlerMapping(endpointMapping, endpoints, endpointMediaTypes,
endpointMediaTypes, corsProperties.toCorsConfiguration(), corsProperties.toCorsConfiguration(),
new EndpointLinksResolver(allEndpoints, new EndpointLinksResolver(allEndpoints, webEndpointProperties.getBasePath()));
webEndpointProperties.getBasePath()));
} }
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public ControllerEndpointHandlerMapping controllerEndpointHandlerMapping( public ControllerEndpointHandlerMapping controllerEndpointHandlerMapping(
ControllerEndpointsSupplier controllerEndpointsSupplier, ControllerEndpointsSupplier controllerEndpointsSupplier, CorsEndpointProperties corsProperties,
CorsEndpointProperties corsProperties,
WebEndpointProperties webEndpointProperties) { WebEndpointProperties webEndpointProperties) {
EndpointMapping endpointMapping = new EndpointMapping( EndpointMapping endpointMapping = new EndpointMapping(webEndpointProperties.getBasePath());
webEndpointProperties.getBasePath()); return new ControllerEndpointHandlerMapping(endpointMapping, controllerEndpointsSupplier.getEndpoints(),
return new ControllerEndpointHandlerMapping(endpointMapping,
controllerEndpointsSupplier.getEndpoints(),
corsProperties.toCorsConfiguration()); corsProperties.toCorsConfiguration());
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -59,36 +59,28 @@ public class WebMvcEndpointManagementContextConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping( public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,
WebEndpointsSupplier webEndpointsSupplier, ServletEndpointsSupplier servletEndpointsSupplier, ControllerEndpointsSupplier controllerEndpointsSupplier,
ServletEndpointsSupplier servletEndpointsSupplier,
ControllerEndpointsSupplier controllerEndpointsSupplier,
EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties, EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties,
WebEndpointProperties webEndpointProperties) { WebEndpointProperties webEndpointProperties) {
List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>(); List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
.getEndpoints();
allEndpoints.addAll(webEndpoints); allEndpoints.addAll(webEndpoints);
allEndpoints.addAll(servletEndpointsSupplier.getEndpoints()); allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints()); allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
EndpointMapping endpointMapping = new EndpointMapping( EndpointMapping endpointMapping = new EndpointMapping(webEndpointProperties.getBasePath());
webEndpointProperties.getBasePath()); return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes,
return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, corsProperties.toCorsConfiguration(),
endpointMediaTypes, corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, webEndpointProperties.getBasePath()));
new EndpointLinksResolver(allEndpoints,
webEndpointProperties.getBasePath()));
} }
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public ControllerEndpointHandlerMapping controllerEndpointHandlerMapping( public ControllerEndpointHandlerMapping controllerEndpointHandlerMapping(
ControllerEndpointsSupplier controllerEndpointsSupplier, ControllerEndpointsSupplier controllerEndpointsSupplier, CorsEndpointProperties corsProperties,
CorsEndpointProperties corsProperties,
WebEndpointProperties webEndpointProperties) { WebEndpointProperties webEndpointProperties) {
EndpointMapping endpointMapping = new EndpointMapping( EndpointMapping endpointMapping = new EndpointMapping(webEndpointProperties.getBasePath());
webEndpointProperties.getBasePath()); return new ControllerEndpointHandlerMapping(endpointMapping, controllerEndpointsSupplier.getEndpoints(),
return new ControllerEndpointHandlerMapping(endpointMapping,
controllerEndpointsSupplier.getEndpoints(),
corsProperties.toCorsConfiguration()); corsProperties.toCorsConfiguration());
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -40,8 +40,7 @@ public class EnvironmentEndpointAutoConfiguration {
private final EnvironmentEndpointProperties properties; private final EnvironmentEndpointProperties properties;
public EnvironmentEndpointAutoConfiguration( public EnvironmentEndpointAutoConfiguration(EnvironmentEndpointProperties properties) {
EnvironmentEndpointProperties properties) {
this.properties = properties; this.properties = properties;
} }
@ -61,8 +60,7 @@ public class EnvironmentEndpointAutoConfiguration {
@ConditionalOnMissingBean @ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint @ConditionalOnEnabledEndpoint
@ConditionalOnBean(EnvironmentEndpoint.class) @ConditionalOnBean(EnvironmentEndpoint.class)
public EnvironmentEndpointWebExtension environmentEndpointWebExtension( public EnvironmentEndpointWebExtension environmentEndpointWebExtension(EnvironmentEndpoint environmentEndpoint) {
EnvironmentEndpoint environmentEndpoint) {
return new EnvironmentEndpointWebExtension(environmentEndpoint); return new EnvironmentEndpointWebExtension(environmentEndpoint);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -42,17 +42,14 @@ public abstract class CompositeHealthIndicatorConfiguration<H extends HealthIndi
if (beans.size() == 1) { if (beans.size() == 1) {
return createHealthIndicator(beans.values().iterator().next()); return createHealthIndicator(beans.values().iterator().next());
} }
CompositeHealthIndicator composite = new CompositeHealthIndicator( CompositeHealthIndicator composite = new CompositeHealthIndicator(this.healthAggregator);
this.healthAggregator); beans.forEach((name, source) -> composite.addHealthIndicator(name, createHealthIndicator(source)));
beans.forEach((name, source) -> composite.addHealthIndicator(name,
createHealthIndicator(source)));
return composite; return composite;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected H createHealthIndicator(S source) { protected H createHealthIndicator(S source) {
Class<?>[] generics = ResolvableType Class<?>[] generics = ResolvableType.forClass(CompositeHealthIndicatorConfiguration.class, getClass())
.forClass(CompositeHealthIndicatorConfiguration.class, getClass())
.resolveGenerics(); .resolveGenerics();
Class<H> indicatorClass = (Class<H>) generics[0]; Class<H> indicatorClass = (Class<H>) generics[0];
Class<S> sourceClass = (Class<S>) generics[1]; Class<S> sourceClass = (Class<S>) generics[1];
@ -60,8 +57,8 @@ public abstract class CompositeHealthIndicatorConfiguration<H extends HealthIndi
return indicatorClass.getConstructor(sourceClass).newInstance(source); return indicatorClass.getConstructor(sourceClass).newInstance(source);
} }
catch (Exception ex) { catch (Exception ex) {
throw new IllegalStateException("Unable to create indicator " + indicatorClass throw new IllegalStateException(
+ " for source " + sourceClass, ex); "Unable to create indicator " + indicatorClass + " for source " + sourceClass, ex);
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -41,17 +41,14 @@ public abstract class CompositeReactiveHealthIndicatorConfiguration<H extends Re
if (beans.size() == 1) { if (beans.size() == 1) {
return createHealthIndicator(beans.values().iterator().next()); return createHealthIndicator(beans.values().iterator().next());
} }
CompositeReactiveHealthIndicator composite = new CompositeReactiveHealthIndicator( CompositeReactiveHealthIndicator composite = new CompositeReactiveHealthIndicator(this.healthAggregator);
this.healthAggregator); beans.forEach((name, source) -> composite.addHealthIndicator(name, createHealthIndicator(source)));
beans.forEach((name, source) -> composite.addHealthIndicator(name,
createHealthIndicator(source)));
return composite; return composite;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected H createHealthIndicator(S source) { protected H createHealthIndicator(S source) {
Class<?>[] generics = ResolvableType Class<?>[] generics = ResolvableType.forClass(CompositeReactiveHealthIndicatorConfiguration.class, getClass())
.forClass(CompositeReactiveHealthIndicatorConfiguration.class, getClass())
.resolveGenerics(); .resolveGenerics();
Class<H> indicatorClass = (Class<H>) generics[0]; Class<H> indicatorClass = (Class<H>) generics[0];
Class<S> sourceClass = (Class<S>) generics[1]; Class<S> sourceClass = (Class<S>) generics[1];
@ -59,8 +56,8 @@ public abstract class CompositeReactiveHealthIndicatorConfiguration<H extends Re
return indicatorClass.getConstructor(sourceClass).newInstance(source); return indicatorClass.getConstructor(sourceClass).newInstance(source);
} }
catch (Exception ex) { catch (Exception ex) {
throw new IllegalStateException("Unable to create indicator " + indicatorClass throw new IllegalStateException(
+ " for source " + sourceClass, ex); "Unable to create indicator " + indicatorClass + " for source " + sourceClass, ex);
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2019 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.
@ -32,11 +32,9 @@ import org.springframework.context.annotation.Import;
* @since 2.0.0 * @since 2.0.0
*/ */
@Configuration @Configuration
@EnableConfigurationProperties({ HealthEndpointProperties.class, @EnableConfigurationProperties({ HealthEndpointProperties.class, HealthIndicatorProperties.class })
HealthIndicatorProperties.class })
@AutoConfigureAfter(HealthIndicatorAutoConfiguration.class) @AutoConfigureAfter(HealthIndicatorAutoConfiguration.class)
@Import({ HealthEndpointConfiguration.class, @Import({ HealthEndpointConfiguration.class, HealthEndpointWebExtensionConfiguration.class })
HealthEndpointWebExtensionConfiguration.class })
public class HealthEndpointAutoConfiguration { public class HealthEndpointAutoConfiguration {
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -51,8 +51,7 @@ class HealthEndpointWebExtensionConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public HealthStatusHttpMapper createHealthStatusHttpMapper( public HealthStatusHttpMapper createHealthStatusHttpMapper(HealthIndicatorProperties healthIndicatorProperties) {
HealthIndicatorProperties healthIndicatorProperties) {
HealthStatusHttpMapper statusHttpMapper = new HealthStatusHttpMapper(); HealthStatusHttpMapper statusHttpMapper = new HealthStatusHttpMapper();
if (healthIndicatorProperties.getHttpMapping() != null) { if (healthIndicatorProperties.getHttpMapping() != null) {
statusHttpMapper.addStatusMapping(healthIndicatorProperties.getHttpMapping()); statusHttpMapper.addStatusMapping(healthIndicatorProperties.getHttpMapping());
@ -62,11 +61,10 @@ class HealthEndpointWebExtensionConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public HealthWebEndpointResponseMapper healthWebEndpointResponseMapper( public HealthWebEndpointResponseMapper healthWebEndpointResponseMapper(HealthStatusHttpMapper statusHttpMapper,
HealthStatusHttpMapper statusHttpMapper,
HealthEndpointProperties properties) { HealthEndpointProperties properties) {
return new HealthWebEndpointResponseMapper(statusHttpMapper, return new HealthWebEndpointResponseMapper(statusHttpMapper, properties.getShowDetails(),
properties.getShowDetails(), properties.getRoles()); properties.getRoles());
} }
@Configuration @Configuration
@ -78,11 +76,9 @@ class HealthEndpointWebExtensionConfiguration {
ReactiveWebHealthConfiguration(ObjectProvider<HealthAggregator> healthAggregator, ReactiveWebHealthConfiguration(ObjectProvider<HealthAggregator> healthAggregator,
ObjectProvider<Map<String, ReactiveHealthIndicator>> reactiveHealthIndicators, ObjectProvider<Map<String, ReactiveHealthIndicator>> reactiveHealthIndicators,
ObjectProvider<Map<String, HealthIndicator>> healthIndicators) { ObjectProvider<Map<String, HealthIndicator>> healthIndicators) {
this.reactiveHealthIndicator = new CompositeReactiveHealthIndicatorFactory() this.reactiveHealthIndicator = new CompositeReactiveHealthIndicatorFactory().createReactiveHealthIndicator(
.createReactiveHealthIndicator(
healthAggregator.getIfAvailable(OrderedHealthAggregator::new), healthAggregator.getIfAvailable(OrderedHealthAggregator::new),
reactiveHealthIndicators reactiveHealthIndicators.getIfAvailable(Collections::emptyMap),
.getIfAvailable(Collections::emptyMap),
healthIndicators.getIfAvailable(Collections::emptyMap)); healthIndicators.getIfAvailable(Collections::emptyMap));
} }
@ -92,8 +88,7 @@ class HealthEndpointWebExtensionConfiguration {
@ConditionalOnBean(HealthEndpoint.class) @ConditionalOnBean(HealthEndpoint.class)
public ReactiveHealthEndpointWebExtension reactiveHealthEndpointWebExtension( public ReactiveHealthEndpointWebExtension reactiveHealthEndpointWebExtension(
HealthWebEndpointResponseMapper responseMapper) { HealthWebEndpointResponseMapper responseMapper) {
return new ReactiveHealthEndpointWebExtension(this.reactiveHealthIndicator, return new ReactiveHealthEndpointWebExtension(this.reactiveHealthIndicator, responseMapper);
responseMapper);
} }
} }
@ -106,11 +101,9 @@ class HealthEndpointWebExtensionConfiguration {
@ConditionalOnMissingBean @ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint @ConditionalOnEnabledEndpoint
@ConditionalOnBean(HealthEndpoint.class) @ConditionalOnBean(HealthEndpoint.class)
public HealthEndpointWebExtension healthEndpointWebExtension( public HealthEndpointWebExtension healthEndpointWebExtension(ApplicationContext applicationContext,
ApplicationContext applicationContext,
HealthWebEndpointResponseMapper responseMapper) { HealthWebEndpointResponseMapper responseMapper) {
return new HealthEndpointWebExtension( return new HealthEndpointWebExtension(HealthIndicatorBeansComposite.get(applicationContext),
HealthIndicatorBeansComposite.get(applicationContext),
responseMapper); responseMapper);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2019 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.
@ -45,15 +45,13 @@ final class HealthIndicatorBeansComposite {
Map<String, HealthIndicator> indicators = new LinkedHashMap<>(); Map<String, HealthIndicator> indicators = new LinkedHashMap<>();
indicators.putAll(applicationContext.getBeansOfType(HealthIndicator.class)); indicators.putAll(applicationContext.getBeansOfType(HealthIndicator.class));
if (ClassUtils.isPresent("reactor.core.publisher.Flux", null)) { if (ClassUtils.isPresent("reactor.core.publisher.Flux", null)) {
new ReactiveHealthIndicators().get(applicationContext) new ReactiveHealthIndicators().get(applicationContext).forEach(indicators::putIfAbsent);
.forEach(indicators::putIfAbsent);
} }
CompositeHealthIndicatorFactory factory = new CompositeHealthIndicatorFactory(); CompositeHealthIndicatorFactory factory = new CompositeHealthIndicatorFactory();
return factory.createHealthIndicator(healthAggregator, indicators); return factory.createHealthIndicator(healthAggregator, indicators);
} }
private static HealthAggregator getHealthAggregator( private static HealthAggregator getHealthAggregator(ApplicationContext applicationContext) {
ApplicationContext applicationContext) {
try { try {
return applicationContext.getBean(HealthAggregator.class); return applicationContext.getBean(HealthAggregator.class);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2019 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.
@ -38,14 +38,12 @@ final class HealthIndicatorBeansReactiveComposite {
public static ReactiveHealthIndicator get(ApplicationContext applicationContext) { public static ReactiveHealthIndicator get(ApplicationContext applicationContext) {
HealthAggregator healthAggregator = getHealthAggregator(applicationContext); HealthAggregator healthAggregator = getHealthAggregator(applicationContext);
return new CompositeReactiveHealthIndicatorFactory() return new CompositeReactiveHealthIndicatorFactory().createReactiveHealthIndicator(healthAggregator,
.createReactiveHealthIndicator(healthAggregator,
applicationContext.getBeansOfType(ReactiveHealthIndicator.class), applicationContext.getBeansOfType(ReactiveHealthIndicator.class),
applicationContext.getBeansOfType(HealthIndicator.class)); applicationContext.getBeansOfType(HealthIndicator.class));
} }
private static HealthAggregator getHealthAggregator( private static HealthAggregator getHealthAggregator(ApplicationContext applicationContext) {
ApplicationContext applicationContext) {
try { try {
return applicationContext.getBean(HealthAggregator.class); return applicationContext.getBean(HealthAggregator.class);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2019 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.
@ -61,8 +61,7 @@ public class InfoContributorAutoConfiguration {
@Bean @Bean
@ConditionalOnEnabledInfoContributor("env") @ConditionalOnEnabledInfoContributor("env")
@Order(DEFAULT_ORDER) @Order(DEFAULT_ORDER)
public EnvironmentInfoContributor envInfoContributor( public EnvironmentInfoContributor envInfoContributor(ConfigurableEnvironment environment) {
ConfigurableEnvironment environment) {
return new EnvironmentInfoContributor(environment); return new EnvironmentInfoContributor(environment);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2019 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.
@ -42,8 +42,7 @@ public class InfoEndpointAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint @ConditionalOnEnabledEndpoint
public InfoEndpoint infoEndpoint( public InfoEndpoint infoEndpoint(ObjectProvider<List<InfoContributor>> infoContributors) {
ObjectProvider<List<InfoContributor>> infoContributors) {
return new InfoEndpoint(infoContributors.getIfAvailable(Collections::emptyList)); return new InfoEndpoint(infoContributors.getIfAvailable(Collections::emptyList));
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -62,8 +62,7 @@ import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
@AutoConfigureBefore(HealthIndicatorAutoConfiguration.class) @AutoConfigureBefore(HealthIndicatorAutoConfiguration.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class) @AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class DataSourceHealthIndicatorAutoConfiguration extends public class DataSourceHealthIndicatorAutoConfiguration extends
CompositeHealthIndicatorConfiguration<DataSourceHealthIndicator, DataSource> CompositeHealthIndicatorConfiguration<DataSourceHealthIndicator, DataSource> implements InitializingBean {
implements InitializingBean {
private final Map<String, DataSource> dataSources; private final Map<String, DataSource> dataSources;
@ -71,15 +70,13 @@ public class DataSourceHealthIndicatorAutoConfiguration extends
private DataSourcePoolMetadataProvider poolMetadataProvider; private DataSourcePoolMetadataProvider poolMetadataProvider;
public DataSourceHealthIndicatorAutoConfiguration( public DataSourceHealthIndicatorAutoConfiguration(ObjectProvider<Map<String, DataSource>> dataSources,
ObjectProvider<Map<String, DataSource>> dataSources,
ObjectProvider<Collection<DataSourcePoolMetadataProvider>> metadataProviders) { ObjectProvider<Collection<DataSourcePoolMetadataProvider>> metadataProviders) {
this.dataSources = filterDataSources(dataSources.getIfAvailable()); this.dataSources = filterDataSources(dataSources.getIfAvailable());
this.metadataProviders = metadataProviders.getIfAvailable(); this.metadataProviders = metadataProviders.getIfAvailable();
} }
private Map<String, DataSource> filterDataSources( private Map<String, DataSource> filterDataSources(Map<String, DataSource> candidates) {
Map<String, DataSource> candidates) {
if (candidates == null) { if (candidates == null) {
return null; return null;
} }
@ -94,8 +91,7 @@ public class DataSourceHealthIndicatorAutoConfiguration extends
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
this.poolMetadataProvider = new CompositeDataSourcePoolMetadataProvider( this.poolMetadataProvider = new CompositeDataSourcePoolMetadataProvider(this.metadataProviders);
this.metadataProviders);
} }
@Bean @Bean
@ -110,8 +106,7 @@ public class DataSourceHealthIndicatorAutoConfiguration extends
} }
private String getValidationQuery(DataSource source) { private String getValidationQuery(DataSource source) {
DataSourcePoolMetadata poolMetadata = this.poolMetadataProvider DataSourcePoolMetadata poolMetadata = this.poolMetadataProvider.getDataSourcePoolMetadata(source);
.getDataSourcePoolMetadata(source);
return (poolMetadata != null) ? poolMetadata.getValidationQuery() : null; return (poolMetadata != null) ? poolMetadata.getValidationQuery() : null;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2019 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.
@ -49,13 +49,12 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnEnabledHealthIndicator("jms") @ConditionalOnEnabledHealthIndicator("jms")
@AutoConfigureBefore(HealthIndicatorAutoConfiguration.class) @AutoConfigureBefore(HealthIndicatorAutoConfiguration.class)
@AutoConfigureAfter({ ActiveMQAutoConfiguration.class, ArtemisAutoConfiguration.class }) @AutoConfigureAfter({ ActiveMQAutoConfiguration.class, ArtemisAutoConfiguration.class })
public class JmsHealthIndicatorAutoConfiguration extends public class JmsHealthIndicatorAutoConfiguration
CompositeHealthIndicatorConfiguration<JmsHealthIndicator, ConnectionFactory> { extends CompositeHealthIndicatorConfiguration<JmsHealthIndicator, ConnectionFactory> {
private final Map<String, ConnectionFactory> connectionFactories; private final Map<String, ConnectionFactory> connectionFactories;
public JmsHealthIndicatorAutoConfiguration( public JmsHealthIndicatorAutoConfiguration(ObjectProvider<Map<String, ConnectionFactory>> connectionFactories) {
ObjectProvider<Map<String, ConnectionFactory>> connectionFactories) {
this.connectionFactories = connectionFactories.getIfAvailable(); this.connectionFactories = connectionFactories.getIfAvailable();
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -42,8 +42,7 @@ public class JolokiaEndpoint implements Supplier<EndpointServlet> {
@Override @Override
public EndpointServlet get() { public EndpointServlet get() {
return new EndpointServlet(AgentServlet.class) return new EndpointServlet(AgentServlet.class).withInitParameters(this.initParameters);
.withInitParameters(this.initParameters);
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2019 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.
@ -47,13 +47,12 @@ import org.springframework.ldap.core.LdapOperations;
@ConditionalOnEnabledHealthIndicator("ldap") @ConditionalOnEnabledHealthIndicator("ldap")
@AutoConfigureBefore(HealthIndicatorAutoConfiguration.class) @AutoConfigureBefore(HealthIndicatorAutoConfiguration.class)
@AutoConfigureAfter(LdapDataAutoConfiguration.class) @AutoConfigureAfter(LdapDataAutoConfiguration.class)
public class LdapHealthIndicatorAutoConfiguration extends public class LdapHealthIndicatorAutoConfiguration
CompositeHealthIndicatorConfiguration<LdapHealthIndicator, LdapOperations> { extends CompositeHealthIndicatorConfiguration<LdapHealthIndicator, LdapOperations> {
private final Map<String, LdapOperations> ldapOperations; private final Map<String, LdapOperations> ldapOperations;
public LdapHealthIndicatorAutoConfiguration( public LdapHealthIndicatorAutoConfiguration(Map<String, LdapOperations> ldapOperations) {
Map<String, LdapOperations> ldapOperations) {
this.ldapOperations = ldapOperations; this.ldapOperations = ldapOperations;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -59,18 +59,15 @@ public class LiquibaseEndpointAutoConfiguration {
return new BeanPostProcessor() { return new BeanPostProcessor() {
@Override @Override
public Object postProcessBeforeInitialization(Object bean, String beanName) public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
throws BeansException {
if (bean instanceof DataSourceClosingSpringLiquibase) { if (bean instanceof DataSourceClosingSpringLiquibase) {
((DataSourceClosingSpringLiquibase) bean) ((DataSourceClosingSpringLiquibase) bean).setCloseDataSourceOnceMigrated(false);
.setCloseDataSourceOnceMigrated(false);
} }
return bean; return bean;
} }
@Override @Override
public Object postProcessAfterInitialization(Object bean, String beanName) public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
throws BeansException {
return bean; return bean;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2019 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.
@ -57,25 +57,20 @@ public class LogFileWebEndpointAutoConfiguration {
private static class LogFileCondition extends SpringBootCondition { private static class LogFileCondition extends SpringBootCondition {
@Override @Override
public ConditionOutcome getMatchOutcome(ConditionContext context, public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment(); Environment environment = context.getEnvironment();
String config = environment.resolvePlaceholders("${logging.file:}"); String config = environment.resolvePlaceholders("${logging.file:}");
ConditionMessage.Builder message = ConditionMessage.forCondition("Log File"); ConditionMessage.Builder message = ConditionMessage.forCondition("Log File");
if (StringUtils.hasText(config)) { if (StringUtils.hasText(config)) {
return ConditionOutcome return ConditionOutcome.match(message.found("logging.file").items(config));
.match(message.found("logging.file").items(config));
} }
config = environment.resolvePlaceholders("${logging.path:}"); config = environment.resolvePlaceholders("${logging.path:}");
if (StringUtils.hasText(config)) { if (StringUtils.hasText(config)) {
return ConditionOutcome return ConditionOutcome.match(message.found("logging.path").items(config));
.match(message.found("logging.path").items(config));
} }
config = environment.getProperty("management.endpoint.logfile.external-file"); config = environment.getProperty("management.endpoint.logfile.external-file");
if (StringUtils.hasText(config)) { if (StringUtils.hasText(config)) {
return ConditionOutcome return ConditionOutcome.match(message.found("management.endpoint.logfile.external-file").items(config));
.match(message.found("management.endpoint.logfile.external-file")
.items(config));
} }
return ConditionOutcome.noMatch(message.didNotFind("logging file").atAll()); return ConditionOutcome.noMatch(message.didNotFind("logging file").atAll());
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -52,14 +52,12 @@ public class LoggersEndpointAutoConfiguration {
static class OnEnabledLoggingSystemCondition extends SpringBootCondition { static class OnEnabledLoggingSystemCondition extends SpringBootCondition {
@Override @Override
public ConditionOutcome getMatchOutcome(ConditionContext context, public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
AnnotatedTypeMetadata metadata) { ConditionMessage.Builder message = ConditionMessage.forCondition("Logging System");
ConditionMessage.Builder message = ConditionMessage
.forCondition("Logging System");
String loggingSystem = System.getProperty(LoggingSystem.SYSTEM_PROPERTY); String loggingSystem = System.getProperty(LoggingSystem.SYSTEM_PROPERTY);
if (LoggingSystem.NONE.equals(loggingSystem)) { if (LoggingSystem.NONE.equals(loggingSystem)) {
return ConditionOutcome.noMatch(message.because("system property " return ConditionOutcome.noMatch(
+ LoggingSystem.SYSTEM_PROPERTY + " is set to none")); message.because("system property " + LoggingSystem.SYSTEM_PROPERTY + " is set to none"));
} }
return ConditionOutcome.match(message.because("enabled")); return ConditionOutcome.match(message.because("enabled"));
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2019 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.
@ -47,13 +47,12 @@ import org.springframework.mail.javamail.JavaMailSenderImpl;
@ConditionalOnEnabledHealthIndicator("mail") @ConditionalOnEnabledHealthIndicator("mail")
@AutoConfigureBefore(HealthIndicatorAutoConfiguration.class) @AutoConfigureBefore(HealthIndicatorAutoConfiguration.class)
@AutoConfigureAfter(MailSenderAutoConfiguration.class) @AutoConfigureAfter(MailSenderAutoConfiguration.class)
public class MailHealthIndicatorAutoConfiguration extends public class MailHealthIndicatorAutoConfiguration
CompositeHealthIndicatorConfiguration<MailHealthIndicator, JavaMailSenderImpl> { extends CompositeHealthIndicatorConfiguration<MailHealthIndicator, JavaMailSenderImpl> {
private final Map<String, JavaMailSenderImpl> mailSenders; private final Map<String, JavaMailSenderImpl> mailSenders;
public MailHealthIndicatorAutoConfiguration( public MailHealthIndicatorAutoConfiguration(ObjectProvider<Map<String, JavaMailSenderImpl>> mailSenders) {
ObjectProvider<Map<String, JavaMailSenderImpl>> mailSenders) {
this.mailSenders = mailSenders.getIfAvailable(); this.mailSenders = mailSenders.getIfAvailable();
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -31,8 +31,7 @@ import org.springframework.context.annotation.Import;
* @since 2.0.0 * @since 2.0.0
*/ */
@Configuration @Configuration
@Import({ NoOpMeterRegistryConfiguration.class, @Import({ NoOpMeterRegistryConfiguration.class, CompositeMeterRegistryConfiguration.class })
CompositeMeterRegistryConfiguration.class })
@ConditionalOnClass(CompositeMeterRegistry.class) @ConditionalOnClass(CompositeMeterRegistry.class)
public class CompositeMeterRegistryAutoConfiguration { public class CompositeMeterRegistryAutoConfiguration {

@ -42,8 +42,7 @@ class CompositeMeterRegistryConfiguration {
@Bean @Bean
@Primary @Primary
public CompositeMeterRegistry compositeMeterRegistry(Clock clock, public CompositeMeterRegistry compositeMeterRegistry(Clock clock, List<MeterRegistry> registries) {
List<MeterRegistry> registries) {
return new CompositeMeterRegistry(clock, registries); return new CompositeMeterRegistry(clock, registries);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -44,10 +44,8 @@ class MeterRegistryConfigurer {
private final boolean addToGlobalRegistry; private final boolean addToGlobalRegistry;
MeterRegistryConfigurer(Collection<MeterBinder> binders, MeterRegistryConfigurer(Collection<MeterBinder> binders, Collection<MeterFilter> filters,
Collection<MeterFilter> filters, Collection<MeterRegistryCustomizer<?>> customizers, boolean addToGlobalRegistry) {
Collection<MeterRegistryCustomizer<?>> customizers,
boolean addToGlobalRegistry) {
this.binders = (binders != null) ? binders : Collections.emptyList(); this.binders = (binders != null) ? binders : Collections.emptyList();
this.filters = (filters != null) ? filters : Collections.emptyList(); this.filters = (filters != null) ? filters : Collections.emptyList();
this.customizers = (customizers != null) ? customizers : Collections.emptyList(); this.customizers = (customizers != null) ? customizers : Collections.emptyList();
@ -68,8 +66,7 @@ class MeterRegistryConfigurer {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void customize(MeterRegistry registry) { private void customize(MeterRegistry registry) {
LambdaSafe.callbacks(MeterRegistryCustomizer.class, this.customizers, registry) LambdaSafe.callbacks(MeterRegistryCustomizer.class, this.customizers, registry)
.withLogger(MeterRegistryConfigurer.class) .withLogger(MeterRegistryConfigurer.class).invoke((customizer) -> customizer.customize(registry));
.invoke((customizer) -> customizer.customize(registry));
} }
private void addFilters(MeterRegistry registry) { private void addFilters(MeterRegistry registry) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -58,8 +58,7 @@ class MeterRegistryPostProcessor implements BeanPostProcessor {
} }
@Override @Override
public Object postProcessAfterInitialization(Object bean, String beanName) public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
throws BeansException {
if (bean instanceof MeterRegistry) { if (bean instanceof MeterRegistry) {
getConfigurer().configure((MeterRegistry) bean); getConfigurer().configure((MeterRegistry) bean);
} }
@ -68,8 +67,7 @@ class MeterRegistryPostProcessor implements BeanPostProcessor {
private MeterRegistryConfigurer getConfigurer() { private MeterRegistryConfigurer getConfigurer() {
if (this.configurer == null) { if (this.configurer == null) {
this.configurer = new MeterRegistryConfigurer( this.configurer = new MeterRegistryConfigurer(this.meterBinders.getIfAvailable(Collections::emptyList),
this.meterBinders.getIfAvailable(Collections::emptyList),
this.meterFilters.getIfAvailable(Collections::emptyList), this.meterFilters.getIfAvailable(Collections::emptyList),
this.meterRegistryCustomizers.getIfAvailable(Collections::emptyList), this.meterRegistryCustomizers.getIfAvailable(Collections::emptyList),
this.metricsProperties.getObject().isUseGlobalRegistry()); this.metricsProperties.getObject().isUseGlobalRegistry());

@ -71,13 +71,11 @@ public class MetricsAutoConfiguration {
} }
@Bean @Bean
public static MeterRegistryPostProcessor meterRegistryPostProcessor( public static MeterRegistryPostProcessor meterRegistryPostProcessor(ObjectProvider<List<MeterBinder>> meterBinders,
ObjectProvider<List<MeterBinder>> meterBinders,
ObjectProvider<List<MeterFilter>> meterFilters, ObjectProvider<List<MeterFilter>> meterFilters,
ObjectProvider<List<MeterRegistryCustomizer<?>>> meterRegistryCustomizers, ObjectProvider<List<MeterRegistryCustomizer<?>>> meterRegistryCustomizers,
ObjectProvider<MetricsProperties> metricsProperties) { ObjectProvider<MetricsProperties> metricsProperties) {
return new MeterRegistryPostProcessor(meterBinders, meterFilters, return new MeterRegistryPostProcessor(meterBinders, meterFilters, meterRegistryCustomizers, metricsProperties);
meterRegistryCustomizers, metricsProperties);
} }
@Bean @Bean
@ -87,8 +85,7 @@ public class MetricsAutoConfiguration {
} }
@Configuration @Configuration
@ConditionalOnProperty(value = "management.metrics.binders.jvm.enabled", @ConditionalOnProperty(value = "management.metrics.binders.jvm.enabled", matchIfMissing = true)
matchIfMissing = true)
static class JvmMeterBindersConfiguration { static class JvmMeterBindersConfiguration {
@Bean @Bean
@ -121,35 +118,30 @@ public class MetricsAutoConfiguration {
static class MeterBindersConfiguration { static class MeterBindersConfiguration {
@Bean @Bean
@ConditionalOnClass(name = { "ch.qos.logback.classic.LoggerContext", @ConditionalOnClass(name = { "ch.qos.logback.classic.LoggerContext", "org.slf4j.LoggerFactory" })
"org.slf4j.LoggerFactory" })
@Conditional(LogbackLoggingCondition.class) @Conditional(LogbackLoggingCondition.class)
@ConditionalOnMissingBean @ConditionalOnMissingBean
@ConditionalOnProperty(value = "management.metrics.binders.logback.enabled", @ConditionalOnProperty(value = "management.metrics.binders.logback.enabled", matchIfMissing = true)
matchIfMissing = true)
public LogbackMetrics logbackMetrics() { public LogbackMetrics logbackMetrics() {
return new LogbackMetrics(); return new LogbackMetrics();
} }
@Bean @Bean
@ConditionalOnProperty(value = "management.metrics.binders.uptime.enabled", @ConditionalOnProperty(value = "management.metrics.binders.uptime.enabled", matchIfMissing = true)
matchIfMissing = true)
@ConditionalOnMissingBean @ConditionalOnMissingBean
public UptimeMetrics uptimeMetrics() { public UptimeMetrics uptimeMetrics() {
return new UptimeMetrics(); return new UptimeMetrics();
} }
@Bean @Bean
@ConditionalOnProperty(value = "management.metrics.binders.processor.enabled", @ConditionalOnProperty(value = "management.metrics.binders.processor.enabled", matchIfMissing = true)
matchIfMissing = true)
@ConditionalOnMissingBean @ConditionalOnMissingBean
public ProcessorMetrics processorMetrics() { public ProcessorMetrics processorMetrics() {
return new ProcessorMetrics(); return new ProcessorMetrics();
} }
@Bean @Bean
@ConditionalOnProperty(name = "management.metrics.binders.files.enabled", @ConditionalOnProperty(name = "management.metrics.binders.files.enabled", matchIfMissing = true)
matchIfMissing = true)
@ConditionalOnMissingBean @ConditionalOnMissingBean
public FileDescriptorMetrics fileDescriptorMetrics() { public FileDescriptorMetrics fileDescriptorMetrics() {
return new FileDescriptorMetrics(); return new FileDescriptorMetrics();
@ -160,18 +152,14 @@ public class MetricsAutoConfiguration {
static class LogbackLoggingCondition extends SpringBootCondition { static class LogbackLoggingCondition extends SpringBootCondition {
@Override @Override
public ConditionOutcome getMatchOutcome(ConditionContext context, public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
AnnotatedTypeMetadata metadata) {
ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory(); ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();
ConditionMessage.Builder message = ConditionMessage ConditionMessage.Builder message = ConditionMessage.forCondition("LogbackLoggingCondition");
.forCondition("LogbackLoggingCondition");
if (loggerFactory instanceof LoggerContext) { if (loggerFactory instanceof LoggerContext) {
return ConditionOutcome.match( return ConditionOutcome.match(message.because("ILoggerFactory is a Logback LoggerContext"));
message.because("ILoggerFactory is a Logback LoggerContext"));
} }
return ConditionOutcome return ConditionOutcome.noMatch(
.noMatch(message.because("ILoggerFactory is an instance of " message.because("ILoggerFactory is an instance of " + loggerFactory.getClass().getCanonicalName()));
+ loggerFactory.getClass().getCanonicalName()));
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -37,8 +37,7 @@ import org.springframework.context.annotation.Configuration;
*/ */
@Configuration @Configuration
@ConditionalOnClass(Timed.class) @ConditionalOnClass(Timed.class)
@AutoConfigureAfter({ MetricsAutoConfiguration.class, @AutoConfigureAfter({ MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class })
CompositeMeterRegistryAutoConfiguration.class })
public class MetricsEndpointAutoConfiguration { public class MetricsEndpointAutoConfiguration {
@Bean @Bean

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -31,8 +31,7 @@ class MissingRequiredConfigurationFailureAnalyzer
extends AbstractFailureAnalyzer<MissingRequiredConfigurationException> { extends AbstractFailureAnalyzer<MissingRequiredConfigurationException> {
@Override @Override
protected FailureAnalysis analyze(Throwable rootFailure, protected FailureAnalysis analyze(Throwable rootFailure, MissingRequiredConfigurationException cause) {
MissingRequiredConfigurationException cause) {
StringBuilder description = new StringBuilder(); StringBuilder description = new StringBuilder();
description.append(cause.getMessage()); description.append(cause.getMessage());
if (!cause.getMessage().endsWith(".")) { if (!cause.getMessage().endsWith(".")) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -36,8 +36,7 @@ import org.springframework.util.Assert;
*/ */
public final class OnlyOnceLoggingDenyMeterFilter implements MeterFilter { public final class OnlyOnceLoggingDenyMeterFilter implements MeterFilter {
private final Logger logger = LoggerFactory private final Logger logger = LoggerFactory.getLogger(OnlyOnceLoggingDenyMeterFilter.class);
.getLogger(OnlyOnceLoggingDenyMeterFilter.class);
private final AtomicBoolean alreadyWarned = new AtomicBoolean(false); private final AtomicBoolean alreadyWarned = new AtomicBoolean(false);
@ -50,8 +49,7 @@ public final class OnlyOnceLoggingDenyMeterFilter implements MeterFilter {
@Override @Override
public MeterFilterReply accept(Meter.Id id) { public MeterFilterReply accept(Meter.Id id) {
if (this.logger.isWarnEnabled() if (this.logger.isWarnEnabled() && this.alreadyWarned.compareAndSet(false, true)) {
&& this.alreadyWarned.compareAndSet(false, true)) {
this.logger.warn(this.message.get()); this.logger.warn(this.message.get());
} }
return MeterFilterReply.DENY; return MeterFilterReply.DENY;

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -53,24 +53,20 @@ public class PropertiesMeterFilter implements MeterFilter {
} }
@Override @Override
public DistributionStatisticConfig configure(Meter.Id id, public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) {
DistributionStatisticConfig config) {
Distribution distribution = this.properties.getDistribution(); Distribution distribution = this.properties.getDistribution();
return DistributionStatisticConfig.builder() return DistributionStatisticConfig.builder()
.percentilesHistogram( .percentilesHistogram(lookup(distribution.getPercentilesHistogram(), id, null))
lookup(distribution.getPercentilesHistogram(), id, null))
.percentiles(lookup(distribution.getPercentiles(), id, null)) .percentiles(lookup(distribution.getPercentiles(), id, null))
.sla(convertSla(id.getType(), lookup(distribution.getSla(), id, null))) .sla(convertSla(id.getType(), lookup(distribution.getSla(), id, null))).build().merge(config);
.build().merge(config);
} }
private long[] convertSla(Meter.Type meterType, ServiceLevelAgreementBoundary[] sla) { private long[] convertSla(Meter.Type meterType, ServiceLevelAgreementBoundary[] sla) {
if (sla == null) { if (sla == null) {
return null; return null;
} }
long[] converted = Arrays.stream(sla) long[] converted = Arrays.stream(sla).map((candidate) -> candidate.getValue(meterType)).filter(Objects::nonNull)
.map((candidate) -> candidate.getValue(meterType)) .mapToLong(Long::longValue).toArray();
.filter(Objects::nonNull).mapToLong(Long::longValue).toArray();
return (converted.length != 0) ? converted : null; return (converted.length != 0) ? converted : null;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -50,19 +50,16 @@ class RabbitConnectionFactoryMetricsPostProcessor implements BeanPostProcessor,
@Override @Override
public Object postProcessAfterInitialization(Object bean, String beanName) { public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof AbstractConnectionFactory) { if (bean instanceof AbstractConnectionFactory) {
bindConnectionFactoryToRegistry(getMeterRegistry(), beanName, bindConnectionFactoryToRegistry(getMeterRegistry(), beanName, (AbstractConnectionFactory) bean);
(AbstractConnectionFactory) bean);
} }
return bean; return bean;
} }
private void bindConnectionFactoryToRegistry(MeterRegistry registry, String beanName, private void bindConnectionFactoryToRegistry(MeterRegistry registry, String beanName,
AbstractConnectionFactory connectionFactory) { AbstractConnectionFactory connectionFactory) {
ConnectionFactory rabbitConnectionFactory = connectionFactory ConnectionFactory rabbitConnectionFactory = connectionFactory.getRabbitConnectionFactory();
.getRabbitConnectionFactory();
String connectionFactoryName = getConnectionFactoryName(beanName); String connectionFactoryName = getConnectionFactoryName(beanName);
new RabbitMetrics(rabbitConnectionFactory, Tags.of("name", connectionFactoryName)) new RabbitMetrics(rabbitConnectionFactory, Tags.of("name", connectionFactoryName)).bindTo(registry);
.bindTo(registry);
} }
/** /**
@ -73,8 +70,7 @@ class RabbitConnectionFactoryMetricsPostProcessor implements BeanPostProcessor,
private String getConnectionFactoryName(String beanName) { private String getConnectionFactoryName(String beanName) {
if (beanName.length() > CONNECTION_FACTORY_SUFFIX.length() if (beanName.length() > CONNECTION_FACTORY_SUFFIX.length()
&& StringUtils.endsWithIgnoreCase(beanName, CONNECTION_FACTORY_SUFFIX)) { && StringUtils.endsWithIgnoreCase(beanName, CONNECTION_FACTORY_SUFFIX)) {
return beanName.substring(0, return beanName.substring(0, beanName.length() - CONNECTION_FACTORY_SUFFIX.length());
beanName.length() - CONNECTION_FACTORY_SUFFIX.length());
} }
return beanName; return beanName;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -43,8 +43,7 @@ import org.springframework.context.annotation.Configuration;
class CacheMeterBinderProvidersConfiguration { class CacheMeterBinderProvidersConfiguration {
@Configuration @Configuration
@ConditionalOnClass({ CaffeineCache.class, @ConditionalOnClass({ CaffeineCache.class, com.github.benmanes.caffeine.cache.Cache.class })
com.github.benmanes.caffeine.cache.Cache.class })
static class CaffeineCacheMeterBinderProviderConfiguration { static class CaffeineCacheMeterBinderProviderConfiguration {
@Bean @Bean

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -36,8 +36,7 @@ import org.springframework.context.annotation.Import;
@Configuration @Configuration
@AutoConfigureAfter({ MetricsAutoConfiguration.class, CacheAutoConfiguration.class }) @AutoConfigureAfter({ MetricsAutoConfiguration.class, CacheAutoConfiguration.class })
@ConditionalOnBean(CacheManager.class) @ConditionalOnBean(CacheManager.class)
@Import({ CacheMeterBinderProvidersConfiguration.class, @Import({ CacheMeterBinderProvidersConfiguration.class, CacheMetricsRegistrarConfiguration.class })
CacheMetricsRegistrarConfiguration.class })
public class CacheMetricsAutoConfiguration { public class CacheMetricsAutoConfiguration {
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -51,8 +51,7 @@ class CacheMetricsRegistrarConfiguration {
private final Map<String, CacheManager> cacheManagers; private final Map<String, CacheManager> cacheManagers;
CacheMetricsRegistrarConfiguration(MeterRegistry registry, CacheMetricsRegistrarConfiguration(MeterRegistry registry, Collection<CacheMeterBinderProvider<?>> binderProviders,
Collection<CacheMeterBinderProvider<?>> binderProviders,
Map<String, CacheManager> cacheManagers) { Map<String, CacheManager> cacheManagers) {
this.registry = registry; this.registry = registry;
this.binderProviders = binderProviders; this.binderProviders = binderProviders;
@ -70,8 +69,8 @@ class CacheMetricsRegistrarConfiguration {
} }
private void bindCacheManagerToRegistry(String beanName, CacheManager cacheManager) { private void bindCacheManagerToRegistry(String beanName, CacheManager cacheManager) {
cacheManager.getCacheNames().forEach((cacheName) -> bindCacheToRegistry(beanName, cacheManager.getCacheNames()
cacheManager.getCache(cacheName))); .forEach((cacheName) -> bindCacheToRegistry(beanName, cacheManager.getCache(cacheName)));
} }
private void bindCacheToRegistry(String beanName, Cache cache) { private void bindCacheToRegistry(String beanName, Cache cache) {
@ -87,8 +86,7 @@ class CacheMetricsRegistrarConfiguration {
private String getCacheManagerName(String beanName) { private String getCacheManagerName(String beanName) {
if (beanName.length() > CACHE_MANAGER_SUFFIX.length() if (beanName.length() > CACHE_MANAGER_SUFFIX.length()
&& StringUtils.endsWithIgnoreCase(beanName, CACHE_MANAGER_SUFFIX)) { && StringUtils.endsWithIgnoreCase(beanName, CACHE_MANAGER_SUFFIX)) {
return beanName.substring(0, return beanName.substring(0, beanName.length() - CACHE_MANAGER_SUFFIX.length());
beanName.length() - CACHE_MANAGER_SUFFIX.length());
} }
return beanName; return beanName;
} }

@ -42,13 +42,12 @@ import org.springframework.context.annotation.Configuration;
* @since 2.0.0 * @since 2.0.0
*/ */
@Configuration @Configuration
@AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, @AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class })
SimpleMetricsExportAutoConfiguration.class })
@AutoConfigureAfter(MetricsAutoConfiguration.class) @AutoConfigureAfter(MetricsAutoConfiguration.class)
@ConditionalOnBean(Clock.class) @ConditionalOnBean(Clock.class)
@ConditionalOnClass(AtlasMeterRegistry.class) @ConditionalOnClass(AtlasMeterRegistry.class)
@ConditionalOnProperty(prefix = "management.metrics.export.atlas", name = "enabled", @ConditionalOnProperty(prefix = "management.metrics.export.atlas", name = "enabled", havingValue = "true",
havingValue = "true", matchIfMissing = true) matchIfMissing = true)
@EnableConfigurationProperties(AtlasProperties.class) @EnableConfigurationProperties(AtlasProperties.class)
public class AtlasMetricsExportAutoConfiguration { public class AtlasMetricsExportAutoConfiguration {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -28,8 +28,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.
* @author Jon Schneider * @author Jon Schneider
* @author Phillip Webb * @author Phillip Webb
*/ */
class AtlasPropertiesConfigAdapter extends PropertiesConfigAdapter<AtlasProperties> class AtlasPropertiesConfigAdapter extends PropertiesConfigAdapter<AtlasProperties> implements AtlasConfig {
implements AtlasConfig {
AtlasPropertiesConfigAdapter(AtlasProperties properties) { AtlasPropertiesConfigAdapter(AtlasProperties properties) {
super(properties); super(properties);
@ -87,8 +86,7 @@ class AtlasPropertiesConfigAdapter extends PropertiesConfigAdapter<AtlasProperti
@Override @Override
public Duration configRefreshFrequency() { public Duration configRefreshFrequency() {
return get(AtlasProperties::getConfigRefreshFrequency, return get(AtlasProperties::getConfigRefreshFrequency, AtlasConfig.super::configRefreshFrequency);
AtlasConfig.super::configRefreshFrequency);
} }
@Override @Override

@ -41,13 +41,12 @@ import org.springframework.context.annotation.Configuration;
* @since 2.0.0 * @since 2.0.0
*/ */
@Configuration @Configuration
@AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, @AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class })
SimpleMetricsExportAutoConfiguration.class })
@AutoConfigureAfter(MetricsAutoConfiguration.class) @AutoConfigureAfter(MetricsAutoConfiguration.class)
@ConditionalOnBean(Clock.class) @ConditionalOnBean(Clock.class)
@ConditionalOnClass(DatadogMeterRegistry.class) @ConditionalOnClass(DatadogMeterRegistry.class)
@ConditionalOnProperty(prefix = "management.metrics.export.datadog", name = "enabled", @ConditionalOnProperty(prefix = "management.metrics.export.datadog", name = "enabled", havingValue = "true",
havingValue = "true", matchIfMissing = true) matchIfMissing = true)
@EnableConfigurationProperties(DatadogProperties.class) @EnableConfigurationProperties(DatadogProperties.class)
public class DatadogMetricsExportAutoConfiguration { public class DatadogMetricsExportAutoConfiguration {
@ -59,8 +58,7 @@ public class DatadogMetricsExportAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public DatadogMeterRegistry datadogMeterRegistry(DatadogConfig datadogConfig, public DatadogMeterRegistry datadogMeterRegistry(DatadogConfig datadogConfig, Clock clock) {
Clock clock) {
return new DatadogMeterRegistry(datadogConfig, clock); return new DatadogMeterRegistry(datadogConfig, clock);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -26,8 +26,8 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.
* @author Jon Schneider * @author Jon Schneider
* @author Phillip Webb * @author Phillip Webb
*/ */
class DatadogPropertiesConfigAdapter extends class DatadogPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<DatadogProperties>
StepRegistryPropertiesConfigAdapter<DatadogProperties> implements DatadogConfig { implements DatadogConfig {
DatadogPropertiesConfigAdapter(DatadogProperties properties) { DatadogPropertiesConfigAdapter(DatadogProperties properties) {
super(properties); super(properties);
@ -40,8 +40,7 @@ class DatadogPropertiesConfigAdapter extends
@Override @Override
public String applicationKey() { public String applicationKey() {
return get(DatadogProperties::getApplicationKey, return get(DatadogProperties::getApplicationKey, DatadogConfig.super::applicationKey);
DatadogConfig.super::applicationKey);
} }
@Override @Override

@ -41,13 +41,12 @@ import org.springframework.context.annotation.Configuration;
* @since 2.0.0 * @since 2.0.0
*/ */
@Configuration @Configuration
@AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, @AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class })
SimpleMetricsExportAutoConfiguration.class })
@AutoConfigureAfter(MetricsAutoConfiguration.class) @AutoConfigureAfter(MetricsAutoConfiguration.class)
@ConditionalOnBean(Clock.class) @ConditionalOnBean(Clock.class)
@ConditionalOnClass(GangliaMeterRegistry.class) @ConditionalOnClass(GangliaMeterRegistry.class)
@ConditionalOnProperty(prefix = "management.metrics.export.ganglia", name = "enabled", @ConditionalOnProperty(prefix = "management.metrics.export.ganglia", name = "enabled", havingValue = "true",
havingValue = "true", matchIfMissing = true) matchIfMissing = true)
@EnableConfigurationProperties(GangliaProperties.class) @EnableConfigurationProperties(GangliaProperties.class)
public class GangliaMetricsExportAutoConfiguration { public class GangliaMetricsExportAutoConfiguration {
@ -59,8 +58,7 @@ public class GangliaMetricsExportAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public GangliaMeterRegistry gangliaMeterRegistry(GangliaConfig gangliaConfig, public GangliaMeterRegistry gangliaMeterRegistry(GangliaConfig gangliaConfig, Clock clock) {
Clock clock) {
return new GangliaMeterRegistry(gangliaConfig, clock); return new GangliaMeterRegistry(gangliaConfig, clock);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -30,8 +30,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.
* @author Jon Schneider * @author Jon Schneider
* @author Phillip Webb * @author Phillip Webb
*/ */
class GangliaPropertiesConfigAdapter extends PropertiesConfigAdapter<GangliaProperties> class GangliaPropertiesConfigAdapter extends PropertiesConfigAdapter<GangliaProperties> implements GangliaConfig {
implements GangliaConfig {
GangliaPropertiesConfigAdapter(GangliaProperties properties) { GangliaPropertiesConfigAdapter(GangliaProperties properties) {
super(properties); super(properties);
@ -59,20 +58,17 @@ class GangliaPropertiesConfigAdapter extends PropertiesConfigAdapter<GangliaProp
@Override @Override
public TimeUnit durationUnits() { public TimeUnit durationUnits() {
return get(GangliaProperties::getDurationUnits, return get(GangliaProperties::getDurationUnits, GangliaConfig.super::durationUnits);
GangliaConfig.super::durationUnits);
} }
@Override @Override
public String protocolVersion() { public String protocolVersion() {
return get(GangliaProperties::getProtocolVersion, return get(GangliaProperties::getProtocolVersion, GangliaConfig.super::protocolVersion);
GangliaConfig.super::protocolVersion);
} }
@Override @Override
public GMetric.UDPAddressingMode addressingMode() { public GMetric.UDPAddressingMode addressingMode() {
return get(GangliaProperties::getAddressingMode, return get(GangliaProperties::getAddressingMode, GangliaConfig.super::addressingMode);
GangliaConfig.super::addressingMode);
} }
@Override @Override

@ -41,13 +41,12 @@ import org.springframework.context.annotation.Configuration;
* @since 2.0.0 * @since 2.0.0
*/ */
@Configuration @Configuration
@AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, @AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class })
SimpleMetricsExportAutoConfiguration.class })
@AutoConfigureAfter(MetricsAutoConfiguration.class) @AutoConfigureAfter(MetricsAutoConfiguration.class)
@ConditionalOnBean(Clock.class) @ConditionalOnBean(Clock.class)
@ConditionalOnClass(GraphiteMeterRegistry.class) @ConditionalOnClass(GraphiteMeterRegistry.class)
@ConditionalOnProperty(prefix = "management.metrics.export.graphite", name = "enabled", @ConditionalOnProperty(prefix = "management.metrics.export.graphite", name = "enabled", havingValue = "true",
havingValue = "true", matchIfMissing = true) matchIfMissing = true)
@EnableConfigurationProperties(GraphiteProperties.class) @EnableConfigurationProperties(GraphiteProperties.class)
public class GraphiteMetricsExportAutoConfiguration { public class GraphiteMetricsExportAutoConfiguration {
@ -59,8 +58,7 @@ public class GraphiteMetricsExportAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public GraphiteMeterRegistry graphiteMeterRegistry(GraphiteConfig graphiteConfig, public GraphiteMeterRegistry graphiteMeterRegistry(GraphiteConfig graphiteConfig, Clock clock) {
Clock clock) {
return new GraphiteMeterRegistry(graphiteConfig, clock); return new GraphiteMeterRegistry(graphiteConfig, clock);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -30,8 +30,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.
* @author Jon Schneider * @author Jon Schneider
* @author Phillip Webb * @author Phillip Webb
*/ */
class GraphitePropertiesConfigAdapter extends PropertiesConfigAdapter<GraphiteProperties> class GraphitePropertiesConfigAdapter extends PropertiesConfigAdapter<GraphiteProperties> implements GraphiteConfig {
implements GraphiteConfig {
GraphitePropertiesConfigAdapter(GraphiteProperties properties) { GraphitePropertiesConfigAdapter(GraphiteProperties properties) {
super(properties); super(properties);
@ -59,8 +58,7 @@ class GraphitePropertiesConfigAdapter extends PropertiesConfigAdapter<GraphitePr
@Override @Override
public TimeUnit durationUnits() { public TimeUnit durationUnits() {
return get(GraphiteProperties::getDurationUnits, return get(GraphiteProperties::getDurationUnits, GraphiteConfig.super::durationUnits);
GraphiteConfig.super::durationUnits);
} }
@Override @Override
@ -80,8 +78,7 @@ class GraphitePropertiesConfigAdapter extends PropertiesConfigAdapter<GraphitePr
@Override @Override
public String[] tagsAsPrefix() { public String[] tagsAsPrefix() {
return get(GraphiteProperties::getTagsAsPrefix, return get(GraphiteProperties::getTagsAsPrefix, GraphiteConfig.super::tagsAsPrefix);
GraphiteConfig.super::tagsAsPrefix);
} }
} }

@ -41,13 +41,12 @@ import org.springframework.context.annotation.Configuration;
* @since 2.0.0 * @since 2.0.0
*/ */
@Configuration @Configuration
@AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, @AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class })
SimpleMetricsExportAutoConfiguration.class })
@AutoConfigureAfter(MetricsAutoConfiguration.class) @AutoConfigureAfter(MetricsAutoConfiguration.class)
@ConditionalOnBean(Clock.class) @ConditionalOnBean(Clock.class)
@ConditionalOnClass(InfluxMeterRegistry.class) @ConditionalOnClass(InfluxMeterRegistry.class)
@ConditionalOnProperty(prefix = "management.metrics.export.influx", name = "enabled", @ConditionalOnProperty(prefix = "management.metrics.export.influx", name = "enabled", havingValue = "true",
havingValue = "true", matchIfMissing = true) matchIfMissing = true)
@EnableConfigurationProperties(InfluxProperties.class) @EnableConfigurationProperties(InfluxProperties.class)
public class InfluxMetricsExportAutoConfiguration { public class InfluxMetricsExportAutoConfiguration {
@ -59,8 +58,7 @@ public class InfluxMetricsExportAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public InfluxMeterRegistry influxMeterRegistry(InfluxConfig influxConfig, public InfluxMeterRegistry influxMeterRegistry(InfluxConfig influxConfig, Clock clock) {
Clock clock) {
return new InfluxMeterRegistry(influxConfig, clock); return new InfluxMeterRegistry(influxConfig, clock);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -27,8 +27,8 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.
* @author Jon Schneider * @author Jon Schneider
* @author Phillip Webb * @author Phillip Webb
*/ */
class InfluxPropertiesConfigAdapter extends class InfluxPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<InfluxProperties>
StepRegistryPropertiesConfigAdapter<InfluxProperties> implements InfluxConfig { implements InfluxConfig {
InfluxPropertiesConfigAdapter(InfluxProperties properties) { InfluxPropertiesConfigAdapter(InfluxProperties properties) {
super(properties); super(properties);
@ -56,26 +56,22 @@ class InfluxPropertiesConfigAdapter extends
@Override @Override
public String retentionPolicy() { public String retentionPolicy() {
return get(InfluxProperties::getRetentionPolicy, return get(InfluxProperties::getRetentionPolicy, InfluxConfig.super::retentionPolicy);
InfluxConfig.super::retentionPolicy);
} }
@Override @Override
public Integer retentionReplicationFactor() { public Integer retentionReplicationFactor() {
return get(InfluxProperties::getRetentionReplicationFactor, return get(InfluxProperties::getRetentionReplicationFactor, InfluxConfig.super::retentionReplicationFactor);
InfluxConfig.super::retentionReplicationFactor);
} }
@Override @Override
public String retentionDuration() { public String retentionDuration() {
return get(InfluxProperties::getRetentionDuration, return get(InfluxProperties::getRetentionDuration, InfluxConfig.super::retentionDuration);
InfluxConfig.super::retentionDuration);
} }
@Override @Override
public String retentionShardDuration() { public String retentionShardDuration() {
return get(InfluxProperties::getRetentionShardDuration, return get(InfluxProperties::getRetentionShardDuration, InfluxConfig.super::retentionShardDuration);
InfluxConfig.super::retentionShardDuration);
} }
@Override @Override

@ -41,13 +41,12 @@ import org.springframework.context.annotation.Configuration;
* @since 2.0.0 * @since 2.0.0
*/ */
@Configuration @Configuration
@AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, @AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class })
SimpleMetricsExportAutoConfiguration.class })
@AutoConfigureAfter(MetricsAutoConfiguration.class) @AutoConfigureAfter(MetricsAutoConfiguration.class)
@ConditionalOnBean(Clock.class) @ConditionalOnBean(Clock.class)
@ConditionalOnClass(JmxMeterRegistry.class) @ConditionalOnClass(JmxMeterRegistry.class)
@ConditionalOnProperty(prefix = "management.metrics.export.jmx", name = "enabled", @ConditionalOnProperty(prefix = "management.metrics.export.jmx", name = "enabled", havingValue = "true",
havingValue = "true", matchIfMissing = true) matchIfMissing = true)
@EnableConfigurationProperties(JmxProperties.class) @EnableConfigurationProperties(JmxProperties.class)
public class JmxMetricsExportAutoConfiguration { public class JmxMetricsExportAutoConfiguration {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -28,8 +28,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.
* @author Jon Schneider * @author Jon Schneider
* @author Stephane Nicoll * @author Stephane Nicoll
*/ */
class JmxPropertiesConfigAdapter extends PropertiesConfigAdapter<JmxProperties> class JmxPropertiesConfigAdapter extends PropertiesConfigAdapter<JmxProperties> implements JmxConfig {
implements JmxConfig {
JmxPropertiesConfigAdapter(JmxProperties properties) { JmxPropertiesConfigAdapter(JmxProperties properties) {
super(properties); super(properties);

@ -42,13 +42,12 @@ import org.springframework.context.annotation.Configuration;
* @since 2.0.0 * @since 2.0.0
*/ */
@Configuration @Configuration
@AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, @AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class })
SimpleMetricsExportAutoConfiguration.class })
@AutoConfigureAfter(MetricsAutoConfiguration.class) @AutoConfigureAfter(MetricsAutoConfiguration.class)
@ConditionalOnBean(Clock.class) @ConditionalOnBean(Clock.class)
@ConditionalOnClass(NewRelicMeterRegistry.class) @ConditionalOnClass(NewRelicMeterRegistry.class)
@ConditionalOnProperty(prefix = "management.metrics.export.newrelic", name = "enabled", @ConditionalOnProperty(prefix = "management.metrics.export.newrelic", name = "enabled", havingValue = "true",
havingValue = "true", matchIfMissing = true) matchIfMissing = true)
@EnableConfigurationProperties(NewRelicProperties.class) @EnableConfigurationProperties(NewRelicProperties.class)
public class NewRelicMetricsExportAutoConfiguration { public class NewRelicMetricsExportAutoConfiguration {
@ -60,8 +59,7 @@ public class NewRelicMetricsExportAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public NewRelicMeterRegistry newRelicMeterRegistry(NewRelicConfig newRelicConfig, public NewRelicMeterRegistry newRelicMeterRegistry(NewRelicConfig newRelicConfig, Clock clock) {
Clock clock) {
return new NewRelicMeterRegistry(newRelicConfig, clock); return new NewRelicMeterRegistry(newRelicConfig, clock);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -26,8 +26,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.
* @author Jon Schneider * @author Jon Schneider
* @since 2.0.0 * @since 2.0.0
*/ */
public class NewRelicPropertiesConfigAdapter public class NewRelicPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<NewRelicProperties>
extends StepRegistryPropertiesConfigAdapter<NewRelicProperties>
implements NewRelicConfig { implements NewRelicConfig {
public NewRelicPropertiesConfigAdapter(NewRelicProperties properties) { public NewRelicPropertiesConfigAdapter(NewRelicProperties properties) {

@ -44,13 +44,12 @@ import org.springframework.context.annotation.Configuration;
* @author Jon Schneider * @author Jon Schneider
*/ */
@Configuration @Configuration
@AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, @AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class })
SimpleMetricsExportAutoConfiguration.class })
@AutoConfigureAfter(MetricsAutoConfiguration.class) @AutoConfigureAfter(MetricsAutoConfiguration.class)
@ConditionalOnBean(Clock.class) @ConditionalOnBean(Clock.class)
@ConditionalOnClass(PrometheusMeterRegistry.class) @ConditionalOnClass(PrometheusMeterRegistry.class)
@ConditionalOnProperty(prefix = "management.metrics.export.prometheus", name = "enabled", @ConditionalOnProperty(prefix = "management.metrics.export.prometheus", name = "enabled", havingValue = "true",
havingValue = "true", matchIfMissing = true) matchIfMissing = true)
@EnableConfigurationProperties(PrometheusProperties.class) @EnableConfigurationProperties(PrometheusProperties.class)
public class PrometheusMetricsExportAutoConfiguration { public class PrometheusMetricsExportAutoConfiguration {
@ -62,9 +61,8 @@ public class PrometheusMetricsExportAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public PrometheusMeterRegistry prometheusMeterRegistry( public PrometheusMeterRegistry prometheusMeterRegistry(PrometheusConfig prometheusConfig,
PrometheusConfig prometheusConfig, CollectorRegistry collectorRegistry, CollectorRegistry collectorRegistry, Clock clock) {
Clock clock) {
return new PrometheusMeterRegistry(prometheusConfig, collectorRegistry, clock); return new PrometheusMeterRegistry(prometheusConfig, collectorRegistry, clock);
} }
@ -80,8 +78,7 @@ public class PrometheusMetricsExportAutoConfiguration {
@Bean @Bean
@ConditionalOnEnabledEndpoint @ConditionalOnEnabledEndpoint
@ConditionalOnMissingBean @ConditionalOnMissingBean
public PrometheusScrapeEndpoint prometheusEndpoint( public PrometheusScrapeEndpoint prometheusEndpoint(CollectorRegistry collectorRegistry) {
CollectorRegistry collectorRegistry) {
return new PrometheusScrapeEndpoint(collectorRegistry); return new PrometheusScrapeEndpoint(collectorRegistry);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -28,8 +28,8 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.
* @author Jon Schneider * @author Jon Schneider
* @author Phillip Webb * @author Phillip Webb
*/ */
class PrometheusPropertiesConfigAdapter extends class PrometheusPropertiesConfigAdapter extends PropertiesConfigAdapter<PrometheusProperties>
PropertiesConfigAdapter<PrometheusProperties> implements PrometheusConfig { implements PrometheusConfig {
PrometheusPropertiesConfigAdapter(PrometheusProperties properties) { PrometheusPropertiesConfigAdapter(PrometheusProperties properties) {
super(properties); super(properties);
@ -42,8 +42,7 @@ class PrometheusPropertiesConfigAdapter extends
@Override @Override
public boolean descriptions() { public boolean descriptions() {
return get(PrometheusProperties::isDescriptions, return get(PrometheusProperties::isDescriptions, PrometheusConfig.super::descriptions);
PrometheusConfig.super::descriptions);
} }
@Override @Override

@ -42,13 +42,12 @@ import org.springframework.context.annotation.Configuration;
* @since 2.0.0 * @since 2.0.0
*/ */
@Configuration @Configuration
@AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, @AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class })
SimpleMetricsExportAutoConfiguration.class })
@AutoConfigureAfter(MetricsAutoConfiguration.class) @AutoConfigureAfter(MetricsAutoConfiguration.class)
@ConditionalOnBean(Clock.class) @ConditionalOnBean(Clock.class)
@ConditionalOnClass(SignalFxMeterRegistry.class) @ConditionalOnClass(SignalFxMeterRegistry.class)
@ConditionalOnProperty(prefix = "management.metrics.export.signalfx", name = "enabled", @ConditionalOnProperty(prefix = "management.metrics.export.signalfx", name = "enabled", havingValue = "true",
havingValue = "true", matchIfMissing = true) matchIfMissing = true)
@EnableConfigurationProperties(SignalFxProperties.class) @EnableConfigurationProperties(SignalFxProperties.class)
public class SignalFxMetricsExportAutoConfiguration { public class SignalFxMetricsExportAutoConfiguration {
@ -60,8 +59,7 @@ public class SignalFxMetricsExportAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public SignalFxMeterRegistry signalFxMeterRegistry(SignalFxConfig config, public SignalFxMeterRegistry signalFxMeterRegistry(SignalFxConfig config, Clock clock) {
Clock clock) {
return new SignalFxMeterRegistry(config, clock); return new SignalFxMeterRegistry(config, clock);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -26,8 +26,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.
* @author Jon Schneider * @author Jon Schneider
* @since 2.0.0 * @since 2.0.0
*/ */
public class SignalFxPropertiesConfigAdapter public class SignalFxPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<SignalFxProperties>
extends StepRegistryPropertiesConfigAdapter<SignalFxProperties>
implements SignalFxConfig { implements SignalFxConfig {
public SignalFxPropertiesConfigAdapter(SignalFxProperties properties) { public SignalFxPropertiesConfigAdapter(SignalFxProperties properties) {

@ -47,8 +47,8 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnBean(Clock.class) @ConditionalOnBean(Clock.class)
@EnableConfigurationProperties(SimpleProperties.class) @EnableConfigurationProperties(SimpleProperties.class)
@ConditionalOnMissingBean(MeterRegistry.class) @ConditionalOnMissingBean(MeterRegistry.class)
@ConditionalOnProperty(prefix = "management.metrics.export.simple", name = "enabled", @ConditionalOnProperty(prefix = "management.metrics.export.simple", name = "enabled", havingValue = "true",
havingValue = "true", matchIfMissing = true) matchIfMissing = true)
public class SimpleMetricsExportAutoConfiguration { public class SimpleMetricsExportAutoConfiguration {
@Bean @Bean

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -29,8 +29,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.
* @author Jon Schneider * @author Jon Schneider
* @since 2.0.0 * @since 2.0.0
*/ */
public class SimplePropertiesConfigAdapter public class SimplePropertiesConfigAdapter extends PropertiesConfigAdapter<SimpleProperties> implements SimpleConfig {
extends PropertiesConfigAdapter<SimpleProperties> implements SimpleConfig {
public SimplePropertiesConfigAdapter(SimpleProperties properties) { public SimplePropertiesConfigAdapter(SimpleProperties properties) {
super(properties); super(properties);

@ -42,13 +42,12 @@ import org.springframework.context.annotation.Configuration;
* @since 2.0.0 * @since 2.0.0
*/ */
@Configuration @Configuration
@AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, @AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class })
SimpleMetricsExportAutoConfiguration.class })
@AutoConfigureAfter(MetricsAutoConfiguration.class) @AutoConfigureAfter(MetricsAutoConfiguration.class)
@ConditionalOnBean(Clock.class) @ConditionalOnBean(Clock.class)
@ConditionalOnClass(StatsdMeterRegistry.class) @ConditionalOnClass(StatsdMeterRegistry.class)
@ConditionalOnProperty(prefix = "management.metrics.export.statsd", name = "enabled", @ConditionalOnProperty(prefix = "management.metrics.export.statsd", name = "enabled", havingValue = "true",
havingValue = "true", matchIfMissing = true) matchIfMissing = true)
@EnableConfigurationProperties(StatsdProperties.class) @EnableConfigurationProperties(StatsdProperties.class)
public class StatsdMetricsExportAutoConfiguration { public class StatsdMetricsExportAutoConfiguration {
@ -60,8 +59,7 @@ public class StatsdMetricsExportAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public StatsdMeterRegistry statsdMeterRegistry(StatsdConfig statsdConfig, public StatsdMeterRegistry statsdMeterRegistry(StatsdConfig statsdConfig, Clock clock) {
Clock clock) {
return new StatsdMeterRegistry(statsdConfig, clock); return new StatsdMeterRegistry(statsdConfig, clock);
} }

@ -124,8 +124,7 @@ public class StatsdProperties {
} }
@Deprecated @Deprecated
@DeprecatedConfigurationProperty( @DeprecatedConfigurationProperty(reason = "No longer configurable and an unbounded queue will always be used")
reason = "No longer configurable and an unbounded queue will always be used")
public Integer getQueueSize() { public Integer getQueueSize() {
return this.queueSize; return this.queueSize;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -29,8 +29,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.
* @author Jon Schneider * @author Jon Schneider
* @since 2.0.0 * @since 2.0.0
*/ */
public class StatsdPropertiesConfigAdapter public class StatsdPropertiesConfigAdapter extends PropertiesConfigAdapter<StatsdProperties> implements StatsdConfig {
extends PropertiesConfigAdapter<StatsdProperties> implements StatsdConfig {
public StatsdPropertiesConfigAdapter(StatsdProperties properties) { public StatsdPropertiesConfigAdapter(StatsdProperties properties) {
super(properties); super(properties);
@ -63,14 +62,12 @@ public class StatsdPropertiesConfigAdapter
@Override @Override
public int maxPacketLength() { public int maxPacketLength() {
return get(StatsdProperties::getMaxPacketLength, return get(StatsdProperties::getMaxPacketLength, StatsdConfig.super::maxPacketLength);
StatsdConfig.super::maxPacketLength);
} }
@Override @Override
public Duration pollingFrequency() { public Duration pollingFrequency() {
return get(StatsdProperties::getPollingFrequency, return get(StatsdProperties::getPollingFrequency, StatsdConfig.super::pollingFrequency);
StatsdConfig.super::pollingFrequency);
} }
@Override @Override
@ -81,8 +78,7 @@ public class StatsdPropertiesConfigAdapter
@Override @Override
public boolean publishUnchangedMeters() { public boolean publishUnchangedMeters() {
return get(StatsdProperties::isPublishUnchangedMeters, return get(StatsdProperties::isPublishUnchangedMeters, StatsdConfig.super::publishUnchangedMeters);
StatsdConfig.super::publishUnchangedMeters);
} }
} }

@ -41,13 +41,12 @@ import org.springframework.context.annotation.Configuration;
* @since 2.0.0 * @since 2.0.0
*/ */
@Configuration @Configuration
@AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, @AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class })
SimpleMetricsExportAutoConfiguration.class })
@AutoConfigureAfter(MetricsAutoConfiguration.class) @AutoConfigureAfter(MetricsAutoConfiguration.class)
@ConditionalOnBean(Clock.class) @ConditionalOnBean(Clock.class)
@ConditionalOnClass(WavefrontMeterRegistry.class) @ConditionalOnClass(WavefrontMeterRegistry.class)
@ConditionalOnProperty(prefix = "management.metrics.export.wavefront", name = "enabled", @ConditionalOnProperty(prefix = "management.metrics.export.wavefront", name = "enabled", havingValue = "true",
havingValue = "true", matchIfMissing = true) matchIfMissing = true)
@EnableConfigurationProperties(WavefrontProperties.class) @EnableConfigurationProperties(WavefrontProperties.class)
public class WavefrontMetricsExportAutoConfiguration { public class WavefrontMetricsExportAutoConfiguration {
@ -59,8 +58,7 @@ public class WavefrontMetricsExportAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public WavefrontMeterRegistry wavefrontMeterRegistry(WavefrontConfig wavefrontConfig, public WavefrontMeterRegistry wavefrontMeterRegistry(WavefrontConfig wavefrontConfig, Clock clock) {
Clock clock) {
return new WavefrontMeterRegistry(wavefrontConfig, clock); return new WavefrontMeterRegistry(wavefrontConfig, clock);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -26,8 +26,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.
* @author Jon Schneider * @author Jon Schneider
* @since 2.0.0 * @since 2.0.0
*/ */
public class WavefrontPropertiesConfigAdapter public class WavefrontPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<WavefrontProperties>
extends StepRegistryPropertiesConfigAdapter<WavefrontProperties>
implements WavefrontConfig { implements WavefrontConfig {
public WavefrontPropertiesConfigAdapter(WavefrontProperties properties) { public WavefrontPropertiesConfigAdapter(WavefrontProperties properties) {
@ -56,8 +55,7 @@ public class WavefrontPropertiesConfigAdapter
@Override @Override
public String globalPrefix() { public String globalPrefix() {
return get(WavefrontProperties::getGlobalPrefix, return get(WavefrontProperties::getGlobalPrefix, WavefrontConfig.super::globalPrefix);
WavefrontConfig.super::globalPrefix);
} }
private String getUriAsString(WavefrontProperties properties) { private String getUriAsString(WavefrontProperties properties) {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -77,8 +77,8 @@ public class DataSourcePoolMetricsAutoConfiguration {
private void bindDataSourceToRegistry(String beanName, DataSource dataSource) { private void bindDataSourceToRegistry(String beanName, DataSource dataSource) {
String dataSourceName = getDataSourceName(beanName); String dataSourceName = getDataSourceName(beanName);
new DataSourcePoolMetrics(dataSource, this.metadataProviders, dataSourceName, new DataSourcePoolMetrics(dataSource, this.metadataProviders, dataSourceName, Collections.emptyList())
Collections.emptyList()).bindTo(this.registry); .bindTo(this.registry);
} }
/** /**
@ -89,8 +89,7 @@ public class DataSourcePoolMetricsAutoConfiguration {
private String getDataSourceName(String beanName) { private String getDataSourceName(String beanName) {
if (beanName.length() > DATASOURCE_SUFFIX.length() if (beanName.length() > DATASOURCE_SUFFIX.length()
&& StringUtils.endsWithIgnoreCase(beanName, DATASOURCE_SUFFIX)) { && StringUtils.endsWithIgnoreCase(beanName, DATASOURCE_SUFFIX)) {
return beanName.substring(0, return beanName.substring(0, beanName.length() - DATASOURCE_SUFFIX.length());
beanName.length() - DATASOURCE_SUFFIX.length());
} }
return beanName; return beanName;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -38,8 +38,7 @@ import org.springframework.core.Ordered;
*/ */
class HikariDataSourceMetricsPostProcessor implements BeanPostProcessor, Ordered { class HikariDataSourceMetricsPostProcessor implements BeanPostProcessor, Ordered {
private static final Log logger = LogFactory private static final Log logger = LogFactory.getLog(HikariDataSourceMetricsPostProcessor.class);
.getLog(HikariDataSourceMetricsPostProcessor.class);
private final ApplicationContext context; private final ApplicationContext context;
@ -65,12 +64,10 @@ class HikariDataSourceMetricsPostProcessor implements BeanPostProcessor, Ordered
return null; return null;
} }
private void bindMetricsRegistryToHikariDataSource(MeterRegistry registry, private void bindMetricsRegistryToHikariDataSource(MeterRegistry registry, HikariDataSource dataSource) {
HikariDataSource dataSource) {
if (!hasExisingMetrics(dataSource)) { if (!hasExisingMetrics(dataSource)) {
try { try {
dataSource.setMetricsTrackerFactory( dataSource.setMetricsTrackerFactory(new MicrometerMetricsTrackerFactory(registry));
new MicrometerMetricsTrackerFactory(registry));
} }
catch (Exception ex) { catch (Exception ex) {
logger.warn("Failed to bind Hikari metrics: " + ex.getMessage()); logger.warn("Failed to bind Hikari metrics: " + ex.getMessage());
@ -79,8 +76,7 @@ class HikariDataSourceMetricsPostProcessor implements BeanPostProcessor, Ordered
} }
private boolean hasExisingMetrics(HikariDataSource dataSource) { private boolean hasExisingMetrics(HikariDataSource dataSource) {
return dataSource.getMetricRegistry() != null return dataSource.getMetricRegistry() != null || dataSource.getMetricsTrackerFactory() != null;
|| dataSource.getMetricsTrackerFactory() != null;
} }
private MeterRegistry getMeterRegistry() { private MeterRegistry getMeterRegistry() {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -65,8 +65,7 @@ public class RestTemplateMetricsAutoConfiguration {
} }
@Bean @Bean
public MetricsRestTemplateCustomizer metricsRestTemplateCustomizer( public MetricsRestTemplateCustomizer metricsRestTemplateCustomizer(MeterRegistry meterRegistry,
MeterRegistry meterRegistry,
RestTemplateExchangeTagsProvider restTemplateTagConfigurer) { RestTemplateExchangeTagsProvider restTemplateTagConfigurer) {
return new MetricsRestTemplateCustomizer(meterRegistry, restTemplateTagConfigurer, return new MetricsRestTemplateCustomizer(meterRegistry, restTemplateTagConfigurer,
this.properties.getWeb().getClient().getRequestsMetricName()); this.properties.getWeb().getClient().getRequestsMetricName());
@ -76,11 +75,11 @@ public class RestTemplateMetricsAutoConfiguration {
@Order(0) @Order(0)
public MeterFilter metricsWebClientUriTagFilter() { public MeterFilter metricsWebClientUriTagFilter() {
String metricName = this.properties.getWeb().getClient().getRequestsMetricName(); String metricName = this.properties.getWeb().getClient().getRequestsMetricName();
MeterFilter denyFilter = new OnlyOnceLoggingDenyMeterFilter(() -> String MeterFilter denyFilter = new OnlyOnceLoggingDenyMeterFilter(
.format("Reached the maximum number of URI tags for '%s'. Are you using " () -> String.format("Reached the maximum number of URI tags for '%s'. Are you using "
+ "'uriVariables' on RestTemplate calls?", metricName)); + "'uriVariables' on RestTemplate calls?", metricName));
return MeterFilter.maximumAllowableTags(metricName, "uri", return MeterFilter.maximumAllowableTags(metricName, "uri", this.properties.getWeb().getClient().getMaxUriTags(),
this.properties.getWeb().getClient().getMaxUriTags(), denyFilter); denyFilter);
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2018 the original author or authors. * Copyright 2012-2019 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.
@ -44,8 +44,7 @@ import org.springframework.core.annotation.Order;
* @since 2.0.0 * @since 2.0.0
*/ */
@Configuration @Configuration
@AutoConfigureAfter({ MetricsAutoConfiguration.class, @AutoConfigureAfter({ MetricsAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class })
SimpleMetricsExportAutoConfiguration.class })
@ConditionalOnBean(MeterRegistry.class) @ConditionalOnBean(MeterRegistry.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class WebFluxMetricsAutoConfiguration { public class WebFluxMetricsAutoConfiguration {
@ -63,8 +62,7 @@ public class WebFluxMetricsAutoConfiguration {
} }
@Bean @Bean
public MetricsWebFilter webfluxMetrics(MeterRegistry registry, public MetricsWebFilter webfluxMetrics(MeterRegistry registry, WebFluxTagsProvider tagConfigurer) {
WebFluxTagsProvider tagConfigurer) {
return new MetricsWebFilter(registry, tagConfigurer, return new MetricsWebFilter(registry, tagConfigurer,
this.properties.getWeb().getServer().getRequestsMetricName(), this.properties.getWeb().getServer().getRequestsMetricName(),
this.properties.getWeb().getServer().isAutoTimeRequests()); this.properties.getWeb().getServer().isAutoTimeRequests());
@ -74,10 +72,10 @@ public class WebFluxMetricsAutoConfiguration {
@Order(0) @Order(0)
public MeterFilter metricsHttpServerUriTagFilter() { public MeterFilter metricsHttpServerUriTagFilter() {
String metricName = this.properties.getWeb().getServer().getRequestsMetricName(); String metricName = this.properties.getWeb().getServer().getRequestsMetricName();
MeterFilter filter = new OnlyOnceLoggingDenyMeterFilter(() -> String MeterFilter filter = new OnlyOnceLoggingDenyMeterFilter(
.format("Reached the maximum number of URI tags for '%s'.", metricName)); () -> String.format("Reached the maximum number of URI tags for '%s'.", metricName));
return MeterFilter.maximumAllowableTags(metricName, "uri", return MeterFilter.maximumAllowableTags(metricName, "uri", this.properties.getWeb().getServer().getMaxUriTags(),
this.properties.getWeb().getServer().getMaxUriTags(), filter); filter);
} }
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save