ConfigReloadOnChange.java
/*
* 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.esigate.extension;
import org.esigate.Driver;
import org.esigate.DriverFactory;
import org.esigate.util.Parameter;
import org.esigate.vars.VariablesResolver;
import org.esigate.util.ParameterLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Properties;
/**
* This extension reloads configuration when esigate.properties is updated.
* <p>
* This only works on configuration defined using "esigate.config" system property.
* <p>
* The polling frequency can be set by adding the following property to esigate configuration : <code>
* <driverid>.configReloadDelay
* </code>
* <p>
* Default polling frequency is 5 seconds.
* <p>
* This class is not intended to use in production.
*
* @author Nicolas Richeton
*
*/
public class ConfigReloadOnChange implements Extension {
private static final long DEFAULT_RELOAD_DELAY = 5000;
/**
* The wait time (ms) between to check for configuration change.
*
*/
public static final Parameter<Long> CONFIG_RELOAD_DELAY = new ParameterLong("configReloadDelay",
DEFAULT_RELOAD_DELAY);
// Do not poll too fast. (ms).
private static final int SPEED_LIMIT = 100;
protected static final Logger LOG = LoggerFactory.getLogger(ConfigReloadOnChange.class);
private static File configuration = null;
private static File variables = null;
private static long configLastModified = -1;
private static long varsLastModified = -1;
private static long delay = DEFAULT_RELOAD_DELAY;
// this variable will be used in the future, when extension supports
// shutdown event.
private static boolean stop = false;
private static Thread fileWatcher = new Thread() {
@Override
public void run() {
while (!stop) {
// configuration
if (configuration != null && configuration.exists()) {
if (configuration.lastModified() != configLastModified) {
configLastModified = configuration.lastModified();
// Reload
LOG.warn("Configuration file changed : reloading.");
DriverFactory.configure();
}
}
// variables
if (variables != null && variables.exists()) {
if (variables.lastModified() != varsLastModified) {
varsLastModified = variables.lastModified();
// Reload
LOG.warn("Variables file changed : reloading.");
VariablesResolver.configure();
}
}
// Wait before checking again
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
stop = true;
LOG.warn("Watching interrupted.");
}
}
LOG.info("Stopped watching {}.", configuration.getAbsoluteFile());
}
};
@Override
public void init(Driver driver, Properties properties) {
// Do nothing if configuration is loaded from the classpath
if (configuration == null) {
LOG.warn("Cannot reload configuration from classpath. Please use -D" + DriverFactory.PROP_CONF_LOCATION);
return;
}
// Load configuration
try {
// Try to convert as long
delay = CONFIG_RELOAD_DELAY.getValue(properties);
// Do not watch faster than SPEED_LIMIT
if (delay < SPEED_LIMIT) {
delay = SPEED_LIMIT;
}
} catch (NumberFormatException e) {
LOG.warn("Unable to convert {}={} as number", CONFIG_RELOAD_DELAY.getName(), e);
}
LOG.info("Will reload configuration every {}ms if {} is modified", delay, configuration.getAbsoluteFile());
}
// This static block ensure thread is started only once.
static {
String envPath = System.getProperty("esigate.config");
if (envPath != null) {
configuration = new File(envPath);
} else {
URL configUrl = DriverFactory.getConfigUrl();
if (configUrl != null && "file".equalsIgnoreCase(configUrl.getProtocol())) {
try {
configuration = new File(configUrl.toURI());
} catch (URISyntaxException e) {
LOG.error("Unable to access configuration file", e);
}
}
}
if (configuration != null && configuration.exists()) {
configLastModified = configuration.lastModified();
}
// variables
URL variablesUrl = VariablesResolver.getVariablessUrl();
if (variablesUrl != null && "file".equalsIgnoreCase(variablesUrl.getProtocol())) {
try {
variables = new File(variablesUrl.toURI());
} catch (URISyntaxException e) {
LOG.error("Unable to access variables file", e);
}
}
if (variables != null && variables.exists()) {
varsLastModified = variables.lastModified();
}
// Start watcher
fileWatcher.start();
}
}