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}