Trigger livereload on remote updates
Add livereload support to RemoteClientConfiguration which is triggered whenever updates are pushed to the remote application. Closes gh-3086
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2012-2015 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.developertools.remote.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.boot.developertools.autoconfigure.OptionalLiveReloadServer;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.client.ClientHttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link Runnable} that waits to triggers live reload until the remote server has
|
||||
* restarted.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class DelayedLiveReloadTrigger implements Runnable {
|
||||
|
||||
private static final long SHUTDOWN_TIME = 1000;
|
||||
|
||||
private static final long SLEEP_TIME = 500;
|
||||
|
||||
private static final long TIMEOUT = 30000;
|
||||
|
||||
private static final Log logger = LogFactory.getLog(DelayedLiveReloadTrigger.class);
|
||||
|
||||
private final OptionalLiveReloadServer liveReloadServer;
|
||||
|
||||
private final ClientHttpRequestFactory requestFactory;
|
||||
|
||||
private final URI uri;
|
||||
|
||||
private long shutdownTime = SHUTDOWN_TIME;
|
||||
|
||||
private long sleepTime = SLEEP_TIME;
|
||||
|
||||
private long timeout = TIMEOUT;
|
||||
|
||||
public DelayedLiveReloadTrigger(OptionalLiveReloadServer liveReloadServer,
|
||||
ClientHttpRequestFactory requestFactory, String url) {
|
||||
Assert.notNull(liveReloadServer, "LiveReloadServer must not be null");
|
||||
Assert.notNull(requestFactory, "RequestFactory must not be null");
|
||||
Assert.hasLength(url, "URL must not be empty");
|
||||
this.liveReloadServer = liveReloadServer;
|
||||
this.requestFactory = requestFactory;
|
||||
try {
|
||||
this.uri = new URI(url);
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
throw new IllegalArgumentException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setTimings(long shutdown, long sleep, long timeout) {
|
||||
this.shutdownTime = shutdown;
|
||||
this.sleepTime = sleep;
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(this.shutdownTime);
|
||||
long start = System.currentTimeMillis();
|
||||
while (!isUp()) {
|
||||
long runTime = System.currentTimeMillis() - start;
|
||||
if (runTime > this.timeout) {
|
||||
return;
|
||||
}
|
||||
Thread.sleep(this.sleepTime);
|
||||
}
|
||||
logger.info("Remote server has changed, triggering LiveReload");
|
||||
this.liveReloadServer.triggerReload();
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isUp() {
|
||||
try {
|
||||
ClientHttpRequest request = createRequest();
|
||||
ClientHttpResponse response = request.execute();
|
||||
return response.getStatusCode() == HttpStatus.OK;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private ClientHttpRequest createRequest() throws IOException {
|
||||
return this.requestFactory.createRequest(this.uri, HttpMethod.GET);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,6 +17,8 @@
|
||||
package org.springframework.boot.developertools.remote.client;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
@@ -24,16 +26,23 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
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.developertools.autoconfigure.DeveloperToolsProperties;
|
||||
import org.springframework.boot.developertools.autoconfigure.OptionalLiveReloadServer;
|
||||
import org.springframework.boot.developertools.autoconfigure.RemoteDeveloperToolsProperties;
|
||||
import org.springframework.boot.developertools.classpath.ClassPathChangedEvent;
|
||||
import org.springframework.boot.developertools.classpath.ClassPathFileSystemWatcher;
|
||||
import org.springframework.boot.developertools.classpath.ClassPathRestartStrategy;
|
||||
import org.springframework.boot.developertools.classpath.PatternClassPathRestartStrategy;
|
||||
import org.springframework.boot.developertools.livereload.LiveReloadServer;
|
||||
import org.springframework.boot.developertools.restart.DefaultRestartInitializer;
|
||||
import org.springframework.boot.developertools.restart.RestartScope;
|
||||
import org.springframework.boot.developertools.restart.Restarter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
@@ -75,6 +84,52 @@ public class RemoteClientConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* LiveReload configuration.
|
||||
*/
|
||||
@ConditionalOnProperty(prefix = "spring.developertools.livereload", name = "enabled", matchIfMissing = true)
|
||||
static class LiveReloadConfiguration {
|
||||
|
||||
@Autowired
|
||||
private DeveloperToolsProperties properties;
|
||||
|
||||
@Autowired(required = false)
|
||||
private LiveReloadServer liveReloadServer;
|
||||
|
||||
@Autowired
|
||||
private ClientHttpRequestFactory clientHttpRequestFactory;
|
||||
|
||||
@Value("${remoteUrl}")
|
||||
private String remoteUrl;
|
||||
|
||||
private ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
|
||||
@Bean
|
||||
@RestartScope
|
||||
@ConditionalOnMissingBean
|
||||
public LiveReloadServer liveReloadServer() {
|
||||
return new LiveReloadServer(this.properties.getLivereload().getPort(),
|
||||
Restarter.getInstance().getThreadFactory());
|
||||
}
|
||||
|
||||
@EventListener
|
||||
public void onClassPathChanged(ClassPathChangedEvent event) {
|
||||
String url = this.remoteUrl + this.properties.getRemote().getContextPath();
|
||||
this.executor.execute(new DelayedLiveReloadTrigger(
|
||||
optionalLiveReloadServer(), this.clientHttpRequestFactory, url));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public OptionalLiveReloadServer optionalLiveReloadServer() {
|
||||
return new OptionalLiveReloadServer(this.liveReloadServer);
|
||||
}
|
||||
|
||||
final ExecutorService getExecutor() {
|
||||
return this.executor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Client configuration for remote update and restarts.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user