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.devtools.autoconfigure; 018 019import java.util.Collection; 020 021import javax.servlet.Filter; 022 023import org.apache.commons.logging.Log; 024import org.apache.commons.logging.LogFactory; 025 026import org.springframework.beans.factory.annotation.Autowired; 027import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 028import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 029import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 030import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 031import org.springframework.boot.autoconfigure.web.ServerProperties; 032import org.springframework.boot.autoconfigure.web.ServerProperties.Servlet; 033import org.springframework.boot.context.properties.EnableConfigurationProperties; 034import org.springframework.boot.devtools.remote.server.AccessManager; 035import org.springframework.boot.devtools.remote.server.Dispatcher; 036import org.springframework.boot.devtools.remote.server.DispatcherFilter; 037import org.springframework.boot.devtools.remote.server.Handler; 038import org.springframework.boot.devtools.remote.server.HandlerMapper; 039import org.springframework.boot.devtools.remote.server.HttpHeaderAccessManager; 040import org.springframework.boot.devtools.remote.server.HttpStatusHandler; 041import org.springframework.boot.devtools.remote.server.UrlHandlerMapper; 042import org.springframework.boot.devtools.restart.server.DefaultSourceFolderUrlFilter; 043import org.springframework.boot.devtools.restart.server.HttpRestartServer; 044import org.springframework.boot.devtools.restart.server.HttpRestartServerHandler; 045import org.springframework.boot.devtools.restart.server.SourceFolderUrlFilter; 046import org.springframework.context.annotation.Bean; 047import org.springframework.context.annotation.Configuration; 048import org.springframework.http.server.ServerHttpRequest; 049 050/** 051 * {@link EnableAutoConfiguration Auto-configuration} for remote development support. 052 * 053 * @author Phillip Webb 054 * @author Rob Winch 055 * @author Andy Wilkinson 056 * @since 1.3.0 057 */ 058@Configuration 059@ConditionalOnProperty(prefix = "spring.devtools.remote", name = "secret") 060@ConditionalOnClass({ Filter.class, ServerHttpRequest.class }) 061@EnableConfigurationProperties({ ServerProperties.class, DevToolsProperties.class }) 062public class RemoteDevToolsAutoConfiguration { 063 064 private static final Log logger = LogFactory 065 .getLog(RemoteDevToolsAutoConfiguration.class); 066 067 private final DevToolsProperties properties; 068 069 private final ServerProperties serverProperties; 070 071 public RemoteDevToolsAutoConfiguration(DevToolsProperties properties, 072 ServerProperties serverProperties) { 073 this.properties = properties; 074 this.serverProperties = serverProperties; 075 } 076 077 @Bean 078 @ConditionalOnMissingBean 079 public AccessManager remoteDevToolsAccessManager() { 080 RemoteDevToolsProperties remoteProperties = this.properties.getRemote(); 081 return new HttpHeaderAccessManager(remoteProperties.getSecretHeaderName(), 082 remoteProperties.getSecret()); 083 } 084 085 @Bean 086 public HandlerMapper remoteDevToolsHealthCheckHandlerMapper() { 087 Handler handler = new HttpStatusHandler(); 088 Servlet servlet = this.serverProperties.getServlet(); 089 String servletContextPath = (servlet.getContextPath() != null) 090 ? servlet.getContextPath() : ""; 091 return new UrlHandlerMapper( 092 servletContextPath + this.properties.getRemote().getContextPath(), 093 handler); 094 } 095 096 @Bean 097 @ConditionalOnMissingBean 098 public DispatcherFilter remoteDevToolsDispatcherFilter(AccessManager accessManager, 099 Collection<HandlerMapper> mappers) { 100 Dispatcher dispatcher = new Dispatcher(accessManager, mappers); 101 return new DispatcherFilter(dispatcher); 102 } 103 104 /** 105 * Configuration for remote update and restarts. 106 */ 107 @Configuration 108 @ConditionalOnProperty(prefix = "spring.devtools.remote.restart", name = "enabled", matchIfMissing = true) 109 static class RemoteRestartConfiguration { 110 111 @Autowired 112 private DevToolsProperties properties; 113 114 @Autowired 115 private ServerProperties serverProperties; 116 117 @Bean 118 @ConditionalOnMissingBean 119 public SourceFolderUrlFilter remoteRestartSourceFolderUrlFilter() { 120 return new DefaultSourceFolderUrlFilter(); 121 } 122 123 @Bean 124 @ConditionalOnMissingBean 125 public HttpRestartServer remoteRestartHttpRestartServer( 126 SourceFolderUrlFilter sourceFolderUrlFilter) { 127 return new HttpRestartServer(sourceFolderUrlFilter); 128 } 129 130 @Bean 131 @ConditionalOnMissingBean(name = "remoteRestartHandlerMapper") 132 public UrlHandlerMapper remoteRestartHandlerMapper(HttpRestartServer server) { 133 Servlet servlet = this.serverProperties.getServlet(); 134 RemoteDevToolsProperties remote = this.properties.getRemote(); 135 String servletContextPath = (servlet.getContextPath() != null) 136 ? servlet.getContextPath() : ""; 137 String url = servletContextPath + remote.getContextPath() + "/restart"; 138 logger.warn("Listening for remote restart updates on " + url); 139 Handler handler = new HttpRestartServerHandler(server); 140 return new UrlHandlerMapper(url, handler); 141 } 142 143 } 144 145}