package com.kostbot.zoodirector.config;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.ConversionException;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.commons.configuration.XMLConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class ZooDirectorConfig {
private static final Logger logger = LoggerFactory.getLogger(ZooDirectorConfig.class);
// Window
private static final String WINDOW = "window";
private static final String WINDOW_WIDTH = WINDOW + ".width";
private static final String WINDOW_HEIGHT = WINDOW + ".height";
protected static final int DEFAULT_WINDOW_WIDTH = 800;
protected static final int DEFAULT_WINDOW_HEIGHT = 600;
// Connection
private static final String CONNECTIONS_BASE = "connections";
// Global connection
protected static final int DEFAULT_CONNECTIONS_RETRY_PERIOD = 5000;
private static final String CONNECTIONS_RETRY_PERIOD = CONNECTIONS_BASE + ".retryPeriod";
// Individual connection
private static final String CONNECTIONS = CONNECTIONS_BASE + ".connection";
private static final String CONNECTION_NAME = "name";
private static final String CONNECTION_VALUE = "value";
private XMLConfiguration config;
/**
* Create a ZooDirector configuration object. If the config file does not exist it will be created (if possible) and
* all configuration changes are auto synced to this file.
*
* @param configFilePath
*/
public ZooDirectorConfig(String configFilePath) {
File configFile = new File(configFilePath);
if (!configFile.exists()) {
config = new XMLConfiguration();
config.setFile(configFile);
config.setAutoSave(true);
logger.info("changes to configuration will be saved to: {}", configFile);
} else {
try {
config = new XMLConfiguration(configFile);
config.setAutoSave(true);
logger.info("loaded configuration file: {}", configFile);
} catch (ConfigurationException e) {
logger.error("failed to load configuration file: {}. any changes to settings will not be persisted", configFile);
config = new XMLConfiguration();
}
}
}
/**
* Get a map of the existing connection aliases. The keys are the alias names and values are the associated
* zookeeper connection strings.
*
* @return a map of connection aliases
*/
public Map<String, String> getConnectionAliases() {
Map<String, String> connectionStrings = new TreeMap<String, String>();
try {
List<HierarchicalConfiguration> aliases = config.configurationsAt(CONNECTIONS);
if (aliases != null) {
for (HierarchicalConfiguration alias : aliases) {
String name = alias.getString(CONNECTION_NAME);
String value = alias.getString(CONNECTION_VALUE, name);
connectionStrings.put(name, value);
}
}
} catch (ConversionException e) {
logger.error("failed to load connection list [{}]", e.getMessage());
}
return connectionStrings;
}
/**
* Add a connection alias
*
* @param name name of alias
* @param value zookeeper connection string
*/
public void addConnectionAlias(String name, String value) {
Map<String, String> aliases = getConnectionAliases();
aliases.put(name, value);
setConnectionAliases(aliases);
}
private String escapeXmlContentString(String content) {
return content.replaceAll(",", "\\\\,");
}
/**
* Clobber the existing connection aliases with the provided set.
*
* @param aliases
*/
public void setConnectionAliases(Map<String, String> aliases) {
config.clearTree(CONNECTIONS);
for (Map.Entry<String, String> aliasEntry : aliases.entrySet()) {
String alias = escapeXmlContentString(aliasEntry.getKey());
String connectionString = escapeXmlContentString(aliasEntry.getValue());
config.addProperty(CONNECTIONS + "(-1)." + CONNECTION_NAME, alias);
config.addProperty(CONNECTIONS + "." + CONNECTION_VALUE, connectionString);
}
}
/**
* Helper method for retrieving integer value properties and falling back to defaultValue if not found or type
* conversion error occurs
*
* @param propertyName property to retrieve from configuration file
* @param defaultValue default value to fall back on on missing property or conversion error
* @return property value if it exist and is an integer, defaultValue otherwise
*/
private int getIntProperty(String propertyName, int defaultValue) {
try {
return config.getInt(propertyName, defaultValue);
} catch (ConversionException e) {
logger.error("failed to load property : {} [{}]", propertyName, e.getMessage());
return defaultValue;
}
}
/**
* Get the customized window width
*
* @return window width property WINDOW_WIDTH if found and is an integer value, else returns default value
*/
public int getWindowWidth() {
return getIntProperty(WINDOW_WIDTH, DEFAULT_WINDOW_WIDTH);
}
/**
* Set the customized window width
*
* @param width
*/
public void setWindowWidth(int width) {
config.setProperty(WINDOW_WIDTH, width);
}
/**
* Get the customized window height
*
* @return window height property "window.height" if found and is an integer value, else returns default value
*/
public int getWindowHeight() {
return getIntProperty(WINDOW_HEIGHT, DEFAULT_WINDOW_HEIGHT);
}
/**
* Set the customized window height
*
* @param height
*/
public void setWindowHeight(int height) {
config.setProperty(WINDOW_HEIGHT, height);
}
/**
* Get the connection retry period. Used for determining when a connection request should be retried.
*
* @return
*/
public int getConnectionRetryPeriod() {
return getIntProperty(CONNECTIONS_RETRY_PERIOD, DEFAULT_CONNECTIONS_RETRY_PERIOD);
}
/**
* Set the connection retry period
*
* @param connectionRetryPeriod
*/
public void setConnectionRetryPeriod(int connectionRetryPeriod) {
config.setProperty(CONNECTIONS_RETRY_PERIOD, connectionRetryPeriod);
}
}