package com.softwaremill.common.conf; import com.google.common.collect.ImmutableMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.softwaremill.common.conf.encoding.ConfigurationValueCoder; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; /** * @author Adam Warski (adam at warski dot org) */ public class Configuration { private static final Logger log = LoggerFactory.getLogger(Configuration.class); private static Map<String, Config<String, String>> configurations = new ConcurrentHashMap<String, Config<String, String>>(); private static List<PropertiesProvider> propertyProviders = new ArrayList<PropertiesProvider>(); private static ConfigurationValueCoder valueCoder = new ConfigurationValueCoder(); /** * Reads configuration for the specified name. * * Will look for a {@code <name>.conf} file in two places: * (1) the jboss conf directory: {@code jboss/server/<current jboss conf>/conf}, if jboss is available * (2) the classpath * * The {@code <name>.conf} should be a simple key-value file. * * @param name Name of the configuration. * @param readSystemPropertiesOnNull flag indicating if System.getProperty() should be called when configuration did not contain a key * @return The properties of the given configuration. */ public static Config<String, String> get(String name, boolean readSystemPropertiesOnNull) { if (configurations.containsKey(name)) { return configurations.get(name); } for (PropertiesProvider propertyProvider : propertyProviders) { Map<String, String> props = propertyProvider.lookupProperties(name); if (props != null) { log.info("Loaded configuration for: " + name + " using " + propertyProvider.getClass().getName()); Config<String, String> conf; if (readSystemPropertiesOnNull) { conf = new SystemPropertiesMapWrapper(props); } else { conf = new MapWrapper(props); } configurations.put(name, conf); return conf; } } throw new RuntimeException("No configuration found for: " + name); } public static Config<String, String> get(String name) { return get(name, false); } public static void registerPropertiesProvider(Class<? extends PropertiesProvider> providerClass) { PropertiesProvider provider; try { provider = providerClass.newInstance(); registerPropertiesProvider(provider); } catch (InstantiationException e) { // do not register } catch (IllegalAccessException e) { // do not register } } public static void registerPropertiesProvider(PropertiesProvider provider) { if (provider.providerAvailable()) { propertyProviders.add(provider); } } public static void setConfiguration(String configurationName, ImmutableMap<String, String> properties) { log.info("Set configuration for: " + configurationName); configurations.put(configurationName, new MapWrapper(properties)); } public static void clearConfiguration(String configurationName) { log.info("Cleared configuration for: " + configurationName); configurations.remove(configurationName); } public static void setFromFile(String configurationName, File file) throws MalformedURLException { ImmutableMap<String, String> conf = loadFromURL(file.toURI().toURL()); setConfiguration(configurationName, conf); } // Registering default property providers. First JBoss (if available), then classpath. static { registerPropertiesProvider(JBoss5DeployPropertiesProvider.class); registerPropertiesProvider(JBoss6DeployPropertiesProvider.class); registerPropertiesProvider(JBoss7DeployPropertiesProvider.class); registerPropertiesProvider(ClasspathPropertiesProvider.class); } static ImmutableMap<String, String> loadFromURL(URL url) { log.info("Loading configuration from URL: " + url); Properties props = new Properties(); try { InputStream is = url.openStream(); try { props.load(is); } finally { is.close(); } ImmutableMap.Builder<String, String> propsAsImmMapBuilder = new ImmutableMap.Builder<String, String>(); for (String propName : props.stringPropertyNames()) { String propValue = props.getProperty(propName); if (valueCoder.isEncoded(propValue)) { propValue = valueCoder.decode(propValue); } propsAsImmMapBuilder = propsAsImmMapBuilder.put(propName, propValue); } return propsAsImmMapBuilder.build(); } catch (FileNotFoundException e) { // Configuration not found in this provider - trying the next one. return null; } catch (IOException e) { log.error("Error while reading configuration from url: " + url.toString(), e); return null; } } }