All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.netflix.config.ConfigurationManager Maven / Gradle / Ivy

There is a newer version: 2.0.0-rc.7
Show newest version
/**
 * Copyright 2014 Netflix, Inc.
 *
 * 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 com.netflix.config;

import com.netflix.config.jmx.ConfigJMXManager;
import com.netflix.config.jmx.ConfigMBean;
import com.netflix.config.util.ConfigurationUtils;

import org.apache.commons.configuration.AbstractConfiguration;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.EnvironmentConfiguration;
import org.apache.commons.configuration.SystemConfiguration;
import org.apache.commons.configuration.event.ConfigurationListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * The configuration manager is a central place where it manages the system wide Configuration and
 * deployment context.
 * 

* During initialization, this class will check system property "archaius.default.configuration.class" * and "archaius.default.configuration.factory". If the former is set, it will use the class name to instantiate * it using its default no-arg constructor. If the later is set, it will call its static method getInstance(). * In both cases, the returned Configuration object will be set as the system wide configuration. * * @author awang * */ public class ConfigurationManager { static volatile AbstractConfiguration instance = null; static volatile boolean customConfigurationInstalled = false; private static volatile ConfigMBean configMBean = null; private static final Logger logger = LoggerFactory.getLogger(ConfigurationManager.class); static volatile DeploymentContext context = null; /** * initStack will hold the stack trace at the time of static initialization for ConfigurationManager * to help debug where/when ConfigurationManager was created. We do this to help debug issues with * Archaius2 where ConfigurationManager is initialized before the bridge has been properly set up */ private static StackTraceElement[] initStack = null; public static final String PROP_NEXT_LOAD = "@next"; public static final String URL_CONFIG_NAME = "archaius.dynamicPropertyFactory.URL_CONFIG"; public static final String SYS_CONFIG_NAME = "archaius.dynamicPropertyFactory.SYS_CONFIG"; public static final String ENV_CONFIG_NAME = "archaius.dynamicPropertyFactory.ENV_CONFIG"; /** * System property to disable adding EnvironmentConfiguration to the default ConcurrentCompositeConfiguration */ public static final String DISABLE_DEFAULT_ENV_CONFIG = "archaius.dynamicProperty.disableEnvironmentConfig"; /** * System property to disable adding SystemConfiguration to the default ConcurrentCompositeConfiguration */ public static final String DISABLE_DEFAULT_SYS_CONFIG = "archaius.dynamicProperty.disableSystemConfig"; private static final String PROP_NEXT_LOAD_NFLX = "netflixconfiguration.properties.nextLoad"; public static final String APPLICATION_PROPERTIES = "APPLICATION_PROPERTIES"; private static Set loadedPropertiesURLs = new CopyOnWriteArraySet(); static { initStack = Thread.currentThread().getStackTrace(); try { String className = System.getProperty("archaius.default.configuration.class"); if (className != null) { instance = (AbstractConfiguration) Class.forName(className).newInstance(); customConfigurationInstalled = true; } else { String factoryName = System.getProperty("archaius.default.configuration.factory"); if (factoryName != null) { Method m = Class.forName(factoryName).getDeclaredMethod("getInstance", new Class[]{}); m.setAccessible(true); instance = (AbstractConfiguration) m.invoke(null, new Object[]{}); customConfigurationInstalled = true; } } String contextClassName = System.getProperty("archaius.default.deploymentContext.class"); if (contextClassName != null) { setDeploymentContext((DeploymentContext) Class.forName(contextClassName).newInstance()); } else { String factoryName = System.getProperty("archaius.default.deploymentContext.factory"); if (factoryName != null) { Method m = Class.forName(factoryName).getDeclaredMethod("getInstance", new Class[]{}); m.setAccessible(true); setDeploymentContext((DeploymentContext) m.invoke(null, new Object[]{})); } else { setDeploymentContext(new ConfigurationBasedDeploymentContext()); } } } catch (Exception e) { throw new RuntimeException("Error initializing configuration", e); } } /** * @return Return the stack trace that triggered static initialization of ConfigurationManager. This * information can be used to help debug static initialization issues with the Archaius2 bridge. */ public static StackTraceElement[] getStaticInitializationSource() { return initStack; } public static Set getLoadedPropertiesURLs() { return loadedPropertiesURLs; } /** * Install the system wide configuration with the ConfigurationManager. This will also install * the configuration with the {@link DynamicPropertyFactory} by calling {@link DynamicPropertyFactory#initWithConfigurationSource(AbstractConfiguration)}. * This call can be made only once, otherwise IllegalStateException will be thrown. */ public static synchronized void install(AbstractConfiguration config) throws IllegalStateException { if (!customConfigurationInstalled) { setDirect(config); if (DynamicPropertyFactory.getBackingConfigurationSource() != config) { DynamicPropertyFactory.initWithConfigurationSource(config); } } else { throw new IllegalStateException("A non-default configuration is already installed"); } } public static synchronized boolean isConfigurationInstalled() { return customConfigurationInstalled; } private static AbstractConfiguration createDefaultConfigInstance() { ConcurrentCompositeConfiguration config = new ConcurrentCompositeConfiguration(); try { DynamicURLConfiguration defaultURLConfig = new DynamicURLConfiguration(); config.addConfiguration(defaultURLConfig, URL_CONFIG_NAME); } catch (Throwable e) { logger.warn("Failed to create default dynamic configuration", e); } if (!Boolean.getBoolean(DISABLE_DEFAULT_SYS_CONFIG)) { SystemConfiguration sysConfig = new SystemConfiguration(); config.addConfiguration(sysConfig, SYS_CONFIG_NAME); } if (!Boolean.getBoolean(DISABLE_DEFAULT_ENV_CONFIG)) { EnvironmentConfiguration envConfig = new EnvironmentConfiguration(); config.addConfiguration(envConfig, ENV_CONFIG_NAME); } ConcurrentCompositeConfiguration appOverrideConfig = new ConcurrentCompositeConfiguration(); config.addConfiguration(appOverrideConfig, APPLICATION_PROPERTIES); config.setContainerConfigurationIndex(config.getIndexOfConfiguration(appOverrideConfig)); return config; } private static AbstractConfiguration getConfigInstance(boolean defaultConfigDisabled) { if (instance == null && !defaultConfigDisabled) { instance = createDefaultConfigInstance(); registerConfigBean(); } return instance; } /** * Get the current system wide configuration. If there has not been set, it will return a default * {@link ConcurrentCompositeConfiguration} which contains a SystemConfiguration from Apache Commons * Configuration and a {@link DynamicURLConfiguration}. */ public static AbstractConfiguration getConfigInstance() { if (instance == null) { synchronized (ConfigurationManager.class) { if (instance == null) { instance = getConfigInstance(Boolean.getBoolean(DynamicPropertyFactory.DISABLE_DEFAULT_CONFIG)); } } } return instance; } private static void registerConfigBean() { if (Boolean.getBoolean(DynamicPropertyFactory.ENABLE_JMX)) { try { configMBean = ConfigJMXManager.registerConfigMbean(instance); } catch (Exception e) { logger.error("Unable to register with JMX", e); } } } static synchronized void setDirect(AbstractConfiguration config) { if (instance != null) { Collection listeners = instance.getConfigurationListeners(); // transfer listeners // transfer properties which are not in conflict with new configuration for (Iterator i = instance.getKeys(); i.hasNext();) { String key = i.next(); Object value = instance.getProperty(key); if (value != null && !config.containsKey(key)) { config.setProperty(key, value); } } if (listeners != null) { for (ConfigurationListener listener: listeners) { if (listener instanceof ExpandedConfigurationListenerAdapter && ((ExpandedConfigurationListenerAdapter) listener).getListener() instanceof DynamicProperty.DynamicPropertyListener) { // no need to transfer the fast property listener as it should be set later // with the new configuration continue; } config.addConfigurationListener(listener); } } } ConfigurationManager.removeDefaultConfiguration(); ConfigurationManager.instance = config; ConfigurationManager.customConfigurationInstalled = true; ConfigurationManager.registerConfigBean(); } /** * Load properties from resource file(s) into the system wide configuration * @param path relative path of the resources * @throws IOException */ public static void loadPropertiesFromResources(String path) throws IOException { if (instance == null) { instance = getConfigInstance(); } ClassLoader loader = Thread.currentThread().getContextClassLoader(); Enumeration resources = loader.getResources(path); if (!resources.hasMoreElements()) { //non-existent config path. Throw an exception. Issue #150 throw new IOException("Cannot locate " + path + " as a classpath resource."); } while (resources.hasMoreElements()) { URL url = resources.nextElement(); InputStream fin = url.openStream(); Properties props = ConfigurationUtils.loadPropertiesFromInputStream(fin); if (instance instanceof AggregatedConfiguration) { String name = getConfigName(url); ConcurrentMapConfiguration config = new ConcurrentMapConfiguration(); config.loadProperties(props); ((AggregatedConfiguration) instance).addConfiguration(config, name); } else { ConfigurationUtils.loadProperties(props, instance); } } } /** * Load resource configName.properties first. Then load configName-deploymentEnvironment.properties * into the system wide configuration. For example, if configName is "application", and deployment environment * is "test", this API will first load "application.properties", then load "application-test.properties" to * override any property that also exist in "application.properties". * * @param configName prefix of the properties file name. * @throws IOException * @see DeploymentContext#getDeploymentEnvironment() */ public static void loadCascadedPropertiesFromResources(String configName) throws IOException { Properties props = loadCascadedProperties(configName); if (instance instanceof AggregatedConfiguration) { ConcurrentMapConfiguration config = new ConcurrentMapConfiguration(); config.loadProperties(props); ((AggregatedConfiguration) instance).addConfiguration(config, configName); } else { ConfigurationUtils.loadProperties(props, instance); } } private static Properties loadCascadedProperties(String configName) throws IOException { String defaultConfigFileName = configName + ".properties"; if (instance == null) { instance = getConfigInstance(); } ClassLoader loader = Thread.currentThread().getContextClassLoader(); URL url = loader.getResource(defaultConfigFileName); if (url == null) { throw new IOException("Cannot locate " + defaultConfigFileName + " as a classpath resource."); } Properties props = getPropertiesFromFile(url); String environment = getDeploymentContext().getDeploymentEnvironment(); if (environment != null && environment.length() > 0) { String envConfigFileName = configName + "-" + environment + ".properties"; url = loader.getResource(envConfigFileName); if (url != null) { Properties envProps = getPropertiesFromFile(url); if (envProps != null) { props.putAll(envProps); } } } return props; } public static void loadAppOverrideProperties(String appConfigName) throws IOException { AbstractConfiguration config = getConfigInstance(); Properties props = loadCascadedProperties(appConfigName); if (config instanceof AggregatedConfiguration) { AggregatedConfiguration aggregated = (AggregatedConfiguration) config; Configuration appConfig = aggregated.getConfiguration(APPLICATION_PROPERTIES); if (appConfig != null) { ConfigurationUtils.loadProperties(props, appConfig); return; } } // The configuration instance is not an aggregated configuration or it does // not have designated configuration for application properties - just add // the properties using config.setProperty() ConfigurationUtils.loadProperties(props, config); } /** * Load properties from the specified configuration into system wide configuration */ public static void loadPropertiesFromConfiguration(AbstractConfiguration config) { if (instance == null) { instance = getConfigInstance(); } if (instance instanceof AggregatedConfiguration) { ((AggregatedConfiguration) instance).addConfiguration(config); } else { Properties props = ConfigurationUtils.getProperties(config); ConfigurationUtils.loadProperties(props, instance); } } /** * Load the specified properties into system wide configuration */ public static void loadProperties(Properties properties) { if (instance == null) { instance = getConfigInstance(); } ConfigurationUtils.loadProperties(properties, instance); } public static void setDeploymentContext(DeploymentContext context) { ConfigurationManager.context = context; if (getConfigInstance() == null) { return; } for (DeploymentContext.ContextKey key: DeploymentContext.ContextKey.values()) { String value = context.getValue(key); if (value != null) { instance.setProperty(key.getKey(), value); } } } public static DeploymentContext getDeploymentContext() { return context; } private static String getConfigName(URL propertyFile) { String name = propertyFile.toExternalForm(); name = name.replace('\\', '/'); // Windows final String scheme = propertyFile.getProtocol().toLowerCase(); if ("jar".equals(scheme) || "zip".equals(scheme)) { // Use the unqualified name of the jar file. final int bang = name.lastIndexOf("!"); if (bang >= 0) { name = name.substring(0, bang); } final int slash = name.lastIndexOf("/"); if (slash >= 0) { name = name.substring(slash + 1); } } else { // Use the URL of the enclosing directory. final int slash = name.lastIndexOf("/"); if (slash >= 0) { name = name.substring(0, slash); } } return name; } private static synchronized void removeDefaultConfiguration() { if (instance == null || customConfigurationInstalled) { return; } ConcurrentCompositeConfiguration defaultConfig = (ConcurrentCompositeConfiguration) instance; // stop loading of the configuration DynamicURLConfiguration defaultFileConfig = (DynamicURLConfiguration) defaultConfig.getConfiguration(URL_CONFIG_NAME); if (defaultFileConfig != null) { defaultFileConfig.stopLoading(); } Collection listeners = defaultConfig.getConfigurationListeners(); // find the listener and remove it so that DynamicProperty will no longer receives // callback from the default configuration source ConfigurationListener dynamicPropertyListener = null; for (ConfigurationListener l: listeners) { if (l instanceof ExpandedConfigurationListenerAdapter && ((ExpandedConfigurationListenerAdapter) l).getListener() instanceof DynamicProperty.DynamicPropertyListener) { dynamicPropertyListener = l; break; } } if (dynamicPropertyListener != null) { defaultConfig.removeConfigurationListener(dynamicPropertyListener); } if (configMBean != null) { try { ConfigJMXManager.unRegisterConfigMBean(defaultConfig, configMBean); } catch (Exception e) { logger.error("Error unregistering with JMX", e); } } instance = null; } public static AbstractConfiguration getConfigFromPropertiesFile(URL startingUrl) throws FileNotFoundException { return ConfigurationUtils.getConfigFromPropertiesFile(startingUrl, getLoadedPropertiesURLs(), PROP_NEXT_LOAD, PROP_NEXT_LOAD_NFLX); } public static Properties getPropertiesFromFile(URL startingUrl) throws FileNotFoundException { return ConfigurationUtils.getPropertiesFromFile(startingUrl, getLoadedPropertiesURLs(), PROP_NEXT_LOAD, PROP_NEXT_LOAD_NFLX); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy