001/* 002 * Copyright 2012-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.boot.actuate.autoconfigure.endpoint.web; 018 019import java.util.Arrays; 020import java.util.Collection; 021import java.util.Collections; 022import java.util.List; 023import java.util.stream.Collectors; 024 025import org.springframework.beans.factory.ObjectProvider; 026import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; 027import org.springframework.boot.actuate.autoconfigure.endpoint.ExposeExcludePropertyEndpointFilter; 028import org.springframework.boot.actuate.endpoint.EndpointFilter; 029import org.springframework.boot.actuate.endpoint.EndpointsSupplier; 030import org.springframework.boot.actuate.endpoint.annotation.Endpoint; 031import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType; 032import org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor; 033import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper; 034import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes; 035import org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint; 036import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint; 037import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints; 038import org.springframework.boot.actuate.endpoint.web.PathMapper; 039import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier; 040import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointDiscoverer; 041import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier; 042import org.springframework.boot.actuate.endpoint.web.annotation.ExposableControllerEndpoint; 043import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointDiscoverer; 044import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier; 045import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer; 046import org.springframework.boot.autoconfigure.AutoConfigureAfter; 047import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 048import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 049import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; 050import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; 051import org.springframework.boot.context.properties.EnableConfigurationProperties; 052import org.springframework.context.ApplicationContext; 053import org.springframework.context.annotation.Bean; 054import org.springframework.context.annotation.Configuration; 055 056/** 057 * {@link EnableAutoConfiguration Auto-configuration} for web {@link Endpoint} support. 058 * 059 * @author Phillip Webb 060 * @author Stephane Nicoll 061 * @since 2.0.0 062 */ 063@Configuration 064@ConditionalOnWebApplication 065@AutoConfigureAfter(EndpointAutoConfiguration.class) 066@EnableConfigurationProperties(WebEndpointProperties.class) 067public class WebEndpointAutoConfiguration { 068 069 private static final List<String> MEDIA_TYPES = Arrays 070 .asList(ActuatorMediaType.V2_JSON, "application/json"); 071 072 private final ApplicationContext applicationContext; 073 074 private final WebEndpointProperties properties; 075 076 public WebEndpointAutoConfiguration(ApplicationContext applicationContext, 077 WebEndpointProperties properties) { 078 this.applicationContext = applicationContext; 079 this.properties = properties; 080 } 081 082 @Bean 083 public PathMapper webEndpointPathMapper() { 084 return new MappingWebEndpointPathMapper(this.properties.getPathMapping()); 085 } 086 087 @Bean 088 @ConditionalOnMissingBean 089 public EndpointMediaTypes endpointMediaTypes() { 090 return new EndpointMediaTypes(MEDIA_TYPES, MEDIA_TYPES); 091 } 092 093 @Bean 094 @ConditionalOnMissingBean(WebEndpointsSupplier.class) 095 public WebEndpointDiscoverer webEndpointDiscoverer( 096 ParameterValueMapper parameterValueMapper, 097 EndpointMediaTypes endpointMediaTypes, 098 ObjectProvider<PathMapper> endpointPathMappers, 099 ObjectProvider<OperationInvokerAdvisor> invokerAdvisors, 100 ObjectProvider<EndpointFilter<ExposableWebEndpoint>> filters) { 101 return new WebEndpointDiscoverer(this.applicationContext, parameterValueMapper, 102 endpointMediaTypes, 103 endpointPathMappers.orderedStream().collect(Collectors.toList()), 104 invokerAdvisors.orderedStream().collect(Collectors.toList()), 105 filters.orderedStream().collect(Collectors.toList())); 106 } 107 108 @Bean 109 @ConditionalOnMissingBean(ControllerEndpointsSupplier.class) 110 public ControllerEndpointDiscoverer controllerEndpointDiscoverer( 111 ObjectProvider<PathMapper> endpointPathMappers, 112 ObjectProvider<Collection<EndpointFilter<ExposableControllerEndpoint>>> filters) { 113 return new ControllerEndpointDiscoverer(this.applicationContext, 114 endpointPathMappers.orderedStream().collect(Collectors.toList()), 115 filters.getIfAvailable(Collections::emptyList)); 116 } 117 118 @Bean 119 @ConditionalOnMissingBean 120 public PathMappedEndpoints pathMappedEndpoints( 121 Collection<EndpointsSupplier<?>> endpointSuppliers, 122 WebEndpointProperties webEndpointProperties) { 123 return new PathMappedEndpoints(webEndpointProperties.getBasePath(), 124 endpointSuppliers); 125 } 126 127 @Bean 128 public ExposeExcludePropertyEndpointFilter<ExposableWebEndpoint> webExposeExcludePropertyEndpointFilter() { 129 WebEndpointProperties.Exposure exposure = this.properties.getExposure(); 130 return new ExposeExcludePropertyEndpointFilter<>(ExposableWebEndpoint.class, 131 exposure.getInclude(), exposure.getExclude(), "info", "health"); 132 } 133 134 @Bean 135 public ExposeExcludePropertyEndpointFilter<ExposableControllerEndpoint> controllerExposeExcludePropertyEndpointFilter() { 136 WebEndpointProperties.Exposure exposure = this.properties.getExposure(); 137 return new ExposeExcludePropertyEndpointFilter<>( 138 ExposableControllerEndpoint.class, exposure.getInclude(), 139 exposure.getExclude()); 140 } 141 142 @Configuration 143 @ConditionalOnWebApplication(type = Type.SERVLET) 144 static class WebEndpointServletConfiguration { 145 146 @Bean 147 @ConditionalOnMissingBean(ServletEndpointsSupplier.class) 148 public ServletEndpointDiscoverer servletEndpointDiscoverer( 149 ApplicationContext applicationContext, 150 ObjectProvider<PathMapper> endpointPathMappers, 151 ObjectProvider<EndpointFilter<ExposableServletEndpoint>> filters) { 152 return new ServletEndpointDiscoverer(applicationContext, 153 endpointPathMappers.orderedStream().collect(Collectors.toList()), 154 filters.orderedStream().collect(Collectors.toList())); 155 } 156 157 } 158 159}