package io.fathom.cloud.server; import io.fathom.cloud.zookeeper.ZookeeperClient; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.util.Map; import java.util.Properties; import java.util.Set; import javax.inject.Inject; import javax.inject.Singleton; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.KeeperException.NoNodeException; import org.apache.zookeeper.data.Stat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fathomdb.Configuration; import com.fathomdb.config.ConfigurationBase; import com.fathomdb.properties.PropertyUtils; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.inject.name.Named; @Singleton public class ClusterConfiguration extends ConfigurationBase { private static final Logger log = LoggerFactory.getLogger(ClusterConfiguration.class); private final Configuration instanceConfig; private final ZookeeperClient zookeeperClient; Map<String, String> propertyMap; @Inject public ClusterConfiguration(@Named("instance") Configuration instanceConfig, ZookeeperClient zookeeperClient) { this.instanceConfig = instanceConfig; this.zookeeperClient = zookeeperClient; } @Override public String lookup(String key, String defaultValue) { String value = instanceConfig.find(key); if (value == null) { value = getPropertyMap().get(key); } else { if (propertyMap.containsKey(key)) { log.warn("Cluster config and instance config both contained key (choosing instance config): {}", key); } } if (value != null) { return value; } return defaultValue; } @Override public File getBasePath() { return instanceConfig.getBasePath(); } @Override public Configuration getChildTree(String prefix) { throw new UnsupportedOperationException(); } @Override public Set<String> getKeys() { Set<String> keys = Sets.newHashSet(); keys.addAll(instanceConfig.getKeys()); keys.addAll(getPropertyMap().keySet()); return keys; } private synchronized Map<String, String> getPropertyMap() { if (propertyMap == null) { try { byte[] data = null; try { Stat stat = new Stat(); data = zookeeperClient.getData("/config", null, stat); } catch (NoNodeException e) { // Ignore log.debug("No cluster config node data"); } catch (KeeperException e) { throw new IllegalArgumentException("Error loading config from zookeeper", e); } Properties properties = new Properties(); if (data != null) { properties.load(new ByteArrayInputStream(data)); } Map<String, String> propertyMap = Maps.newHashMap(); PropertyUtils.copyToMap(properties, propertyMap); this.propertyMap = propertyMap; } catch (IOException e) { throw new IllegalArgumentException("Error loading config from zookeeper", e); } } return propertyMap; } }