/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.devtools.autoconfigure;
import java.io.File;
import java.net.URL;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.devtools.autoconfigure.DevToolsProperties.Restart;
import org.springframework.boot.devtools.classpath.ClassPathChangedEvent;
import org.springframework.boot.devtools.classpath.ClassPathFileSystemWatcher;
import org.springframework.boot.devtools.classpath.ClassPathRestartStrategy;
import org.springframework.boot.devtools.classpath.PatternClassPathRestartStrategy;
import org.springframework.boot.devtools.filewatch.FileSystemWatcher;
import org.springframework.boot.devtools.filewatch.FileSystemWatcherFactory;
import org.springframework.boot.devtools.livereload.LiveReloadServer;
import org.springframework.boot.devtools.restart.ConditionalOnInitializedRestarter;
import org.springframework.boot.devtools.restart.RestartScope;
import org.springframework.boot.devtools.restart.Restarter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.util.StringUtils;
/**
* {@link EnableAutoConfiguration Auto-configuration} for local development support.
*
* @author Phillip Webb
* @author Andy Wilkinson
* @author Vladimir Tsanev
* @since 1.3.0
*/
@Configuration
@ConditionalOnInitializedRestarter
@EnableConfigurationProperties(DevToolsProperties.class)
public class LocalDevToolsAutoConfiguration {
/**
* Local LiveReload configuration.
*/
@ConditionalOnProperty(prefix = "spring.devtools.livereload", name = "enabled", matchIfMissing = true)
static class LiveReloadConfiguration {
@Autowired
private DevToolsProperties properties;
@Autowired(required = false)
private LiveReloadServer liveReloadServer;
@Bean
@RestartScope
@ConditionalOnMissingBean
public LiveReloadServer liveReloadServer() {
return new LiveReloadServer(this.properties.getLivereload().getPort(),
Restarter.getInstance().getThreadFactory());
}
@EventListener
public void onContextRefreshed(ContextRefreshedEvent event) {
optionalLiveReloadServer().triggerReload();
}
@EventListener
public void onClassPathChanged(ClassPathChangedEvent event) {
if (!event.isRestartRequired()) {
optionalLiveReloadServer().triggerReload();
}
}
@Bean
public OptionalLiveReloadServer optionalLiveReloadServer() {
return new OptionalLiveReloadServer(this.liveReloadServer);
}
}
/**
* Local Restart Configuration.
*/
@ConditionalOnProperty(prefix = "spring.devtools.restart", name = "enabled", matchIfMissing = true)
static class RestartConfiguration {
@Autowired
private DevToolsProperties properties;
@EventListener
public void onClassPathChanged(ClassPathChangedEvent event) {
if (event.isRestartRequired()) {
Restarter.getInstance().restart(
new FileWatchingFailureHandler(fileSystemWatcherFactory()));
}
}
@Bean
@ConditionalOnMissingBean
public ClassPathFileSystemWatcher classPathFileSystemWatcher() {
URL[] urls = Restarter.getInstance().getInitialUrls();
ClassPathFileSystemWatcher watcher = new ClassPathFileSystemWatcher(
fileSystemWatcherFactory(), classPathRestartStrategy(), urls);
watcher.setStopWatcherOnRestart(true);
return watcher;
}
@Bean
@ConditionalOnMissingBean
public ClassPathRestartStrategy classPathRestartStrategy() {
return new PatternClassPathRestartStrategy(
this.properties.getRestart().getAllExclude());
}
@Bean
public HateoasObjenesisCacheDisabler hateoasObjenesisCacheDisabler() {
return new HateoasObjenesisCacheDisabler();
}
@Bean
public FileSystemWatcherFactory fileSystemWatcherFactory() {
return new FileSystemWatcherFactory() {
@Override
public FileSystemWatcher getFileSystemWatcher() {
return newFileSystemWatcher();
}
};
}
private FileSystemWatcher newFileSystemWatcher() {
Restart restartProperties = this.properties.getRestart();
FileSystemWatcher watcher = new FileSystemWatcher(true,
restartProperties.getPollInterval(),
restartProperties.getQuietPeriod());
String triggerFile = restartProperties.getTriggerFile();
if (StringUtils.hasLength(triggerFile)) {
watcher.setTriggerFilter(new TriggerFileFilter(triggerFile));
}
List<File> additionalPaths = restartProperties.getAdditionalPaths();
for (File path : additionalPaths) {
watcher.addSourceFolder(path.getAbsoluteFile());
}
return watcher;
}
}
}