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.web.server;
018
019import java.util.Arrays;
020import java.util.Collections;
021import java.util.List;
022import java.util.Objects;
023import java.util.stream.Collectors;
024
025import org.springframework.beans.factory.BeanFactoryUtils;
026import org.springframework.beans.factory.ListableBeanFactory;
027import org.springframework.beans.factory.NoSuchBeanDefinitionException;
028import org.springframework.boot.autoconfigure.web.ServerProperties;
029import org.springframework.boot.util.LambdaSafe;
030import org.springframework.boot.web.server.ConfigurableWebServerFactory;
031import org.springframework.boot.web.server.ErrorPage;
032import org.springframework.boot.web.server.Ssl;
033import org.springframework.boot.web.server.WebServerFactory;
034import org.springframework.boot.web.server.WebServerFactoryCustomizer;
035import org.springframework.core.Ordered;
036
037/**
038 * {@link WebServerFactoryCustomizer} that customizes the {@link WebServerFactory} used to
039 * create the management context's web server.
040 *
041 * @param <T> the type of web server factory to customize
042 * @author Andy Wilkinson
043 * @since 2.0.0
044 */
045public abstract class ManagementWebServerFactoryCustomizer<T extends ConfigurableWebServerFactory>
046                implements WebServerFactoryCustomizer<T>, Ordered {
047
048        private final ListableBeanFactory beanFactory;
049
050        private final Class<? extends WebServerFactoryCustomizer<?>>[] customizerClasses;
051
052        @SafeVarargs
053        protected ManagementWebServerFactoryCustomizer(ListableBeanFactory beanFactory,
054                        Class<? extends WebServerFactoryCustomizer<?>>... customizerClasses) {
055                this.beanFactory = beanFactory;
056                this.customizerClasses = customizerClasses;
057        }
058
059        @Override
060        public int getOrder() {
061                return 0;
062        }
063
064        @Override
065        public final void customize(T factory) {
066                ManagementServerProperties managementServerProperties = BeanFactoryUtils
067                                .beanOfTypeIncludingAncestors(this.beanFactory,
068                                                ManagementServerProperties.class);
069                // Customize as per the parent context first (so e.g. the access logs go to
070                // the same place)
071                customizeSameAsParentContext(factory);
072                // Then reset the error pages
073                factory.setErrorPages(Collections.emptySet());
074                // and add the management-specific bits
075                ServerProperties serverProperties = BeanFactoryUtils
076                                .beanOfTypeIncludingAncestors(this.beanFactory, ServerProperties.class);
077                customize(factory, managementServerProperties, serverProperties);
078        }
079
080        private void customizeSameAsParentContext(T factory) {
081                List<WebServerFactoryCustomizer<?>> customizers = Arrays
082                                .stream(this.customizerClasses).map(this::getCustomizer)
083                                .filter(Objects::nonNull).collect(Collectors.toList());
084                invokeCustomizers(factory, customizers);
085        }
086
087        private WebServerFactoryCustomizer<?> getCustomizer(
088                        Class<? extends WebServerFactoryCustomizer<?>> customizerClass) {
089                try {
090                        return BeanFactoryUtils.beanOfTypeIncludingAncestors(this.beanFactory,
091                                        customizerClass);
092                }
093                catch (NoSuchBeanDefinitionException ex) {
094                        return null;
095                }
096        }
097
098        @SuppressWarnings("unchecked")
099        private void invokeCustomizers(T factory,
100                        List<WebServerFactoryCustomizer<?>> customizers) {
101                LambdaSafe.callbacks(WebServerFactoryCustomizer.class, customizers, factory)
102                                .invoke((customizer) -> customizer.customize(factory));
103        }
104
105        protected void customize(T factory,
106                        ManagementServerProperties managementServerProperties,
107                        ServerProperties serverProperties) {
108                factory.setPort(managementServerProperties.getPort());
109                Ssl ssl = managementServerProperties.getSsl();
110                if (ssl != null) {
111                        factory.setSsl(ssl);
112                }
113                factory.setServerHeader(serverProperties.getServerHeader());
114                factory.setAddress(managementServerProperties.getAddress());
115                factory.addErrorPages(new ErrorPage(serverProperties.getError().getPath()));
116        }
117
118}