<commit_before>/*
 *
 *  Copyright 2012 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 java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Collection;
import java.util.Properties;

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

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

/**
 * The configuration manager is a central place where it manages the system wide Configuration and
 * deployment context.
 * <p>
 * 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;
    
    static {
        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) {
                context = (DeploymentContext) Class.forName(className).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);
                    context = (DeploymentContext) m.invoke(null, new Object[]{});
                } else {
                    context = new ConfigurationBasedDeploymentContext();
                }
            }

        } catch (Exception e) {
            throw new RuntimeException("Error initializing configuration", e);
        }
    }
    
    /**
     * 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) {
            if (instance != null) {
                removeDefaultConfiguration();
            }
            instance = config;
            if (DynamicPropertyFactory.getBackingConfigurationSource() != config) {                
                DynamicPropertyFactory.initWithConfigurationSource(config);
            }
            customConfigurationInstalled = true;
            registerConfigBean();
        } 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();            
        if (!Boolean.getBoolean(DynamicPropertyFactory.DISABLE_DEFAULT_SYS_CONFIG)) {
            SystemConfiguration sysConfig = new SystemConfiguration();                
            config.addConfiguration(sysConfig, DynamicPropertyFactory.SYS_CONFIG_NAME);
            try {
                DynamicURLConfiguration defaultURLConfig = new DynamicURLConfiguration();
                config.addConfiguration(defaultURLConfig, DynamicPropertyFactory.URL_CONFIG_NAME);
            } catch (Throwable e) {
                logger.warn("Failed to create default dynamic configuration", e);
            }
        }
        return config;
    }
    
    private static AbstractConfiguration getConfigInstance(boolean defaultConfigDisabled) {
        if (instance == null) {
            synchronized (ConfigurationManager.class) {
                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) {
        ConfigurationManager.removeDefaultConfiguration();
        ConfigurationManager.instance = config;
        ConfigurationManager.customConfigurationInstalled = true;
        ConfigurationManager.registerConfigBean();
    }
        
    /**
     * Load properties from resource file into the system wide configuration
     * @param path path of the resource
     * @throws IOException
     */
    public static void loadPropertiesFromResources(String path) 
            throws IOException {
        if (instance == null) {
            instance = getConfigInstance();
        }
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        URL url = loader.getResource(path);
        if (url == null) {
            throw new IOException("Cannot locate " + path + " as a classpath resource.");
        }
        Properties props = new Properties();
        InputStream fin = url.openStream();
        props.load(fin);
        fin.close();
        if (instance instanceof AggregatedConfiguration) {
            String name = getConfigName(url);
            ConcurrentMapConfiguration config = new ConcurrentMapConfiguration();
            config.loadProperties(props);<commit_msg>Transfer listeners and properties before removing default configuration instance.<commit_after>/*
 *
 *  Copyright 2012 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 java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

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

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

/**
 * The configuration manager is a central place where it manages the system wide Configuration and
 * deployment context.
 * <p>
 * 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;
    
    static {
        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) {
                context = (DeploymentContext) Class.forName(className).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);
                    context = (DeploymentContext) m.invoke(null, new Object[]{});
                } else {
                    context = new ConfigurationBasedDeploymentContext();
                }
            }

        } catch (Exception e) {
            throw new RuntimeException("Error initializing configuration", e);
        }
    }
    
    /**
     * 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) {
            if (instance != null) {
                removeDefaultConfiguration();
            }
            instance = config;
            if (DynamicPropertyFactory.getBackingConfigurationSource() != config) {                
                DynamicPropertyFactory.initWithConfigurationSource(config);
            }
            customConfigurationInstalled = true;
            registerConfigBean();
        } 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();            
        if (!Boolean.getBoolean(DynamicPropertyFactory.DISABLE_DEFAULT_SYS_CONFIG)) {
            SystemConfiguration sysConfig = new SystemConfiguration();                
            config.addConfiguration(sysConfig, DynamicPropertyFactory.SYS_CONFIG_NAME);
            try {
                DynamicURLConfiguration defaultURLConfig = new DynamicURLConfiguration();
                config.addConfiguration(defaultURLConfig, DynamicPropertyFactory.URL_CONFIG_NAME);
            } catch (Throwable e) {
                logger.warn("Failed to create default dynamic configuration", e);
            }
        }
        return config;
    }
    
    private static AbstractConfiguration getConfigInstance(boolean defaultConfigDisabled) {
        if (instance == null) {
            synchronized (ConfigurationManager.class) {
                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<ConfigurationListener> listeners = instance.getConfigurationListeners();
            // transfer listeners
            if (listeners != null) {
                for (ConfigurationListener listener: listeners) {
                    config.addConfigurationListener(listener);
                }
            }
            // transfer properties
            for (Iterator<String> i = instance.getKeys(); i.hasNext();) {
                String key = i.next();
                Object value = config.getProperty(key);
                if (value != null) {
                    config.setProperty(key, value);
                }
            }
        }
        ConfigurationManager.removeDefaultConfiguration();
        ConfigurationManager.instance = config;
        ConfigurationManager.customConfigurationInstalled = true;
        ConfigurationManager.registerConfigBean();
    }
        
    /**
     * Load properties from resource file into the system wide configuration
     * @param path path of the resource
     * @throws IOException
     */
    public static void loadPropertiesFromResources(String path) 
            throws IOException {
        if (instance == null) {
            instance = getConfigInstance();
        }
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        URL url = loader.getResource(path);
        if (url == null) {
            throw new IOException("Cannot locate " + path + " as a classpath resource.");
        }
        Properties props = new Properties();
        InputStream fin = url.openStream();
        props.load(fin);
        fin.close();
        if (instance instanceof AggregatedConfiguration) {
            String name = getConfigName(url);
            ConcurrentMapConfiguration config = new ConcurrentMapConfiguration();
            config.loadProperties(props);
{'fraction_non_alphanumeric': 0.07839769516316693, 'fraction_numerical': 0.0011080946312815114, 'mean_word_length': 2.431558935361217, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3317645', 'n_tokens_mistral': 4033, 'n_tokens_neox': 3954, 'n_words': 1175}