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

com.redhat.ceylon.common.config.ConfigFinder Maven / Gradle / Ivy

There is a newer version: 1.3.3
Show newest version
package com.redhat.ceylon.common.config;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import com.redhat.ceylon.common.Constants;
import com.redhat.ceylon.common.FileUtil;

/**
 * This class' main function is to locate configuration files, parse them
 * using ConfigParser and return CeylonConfig objects containing the
 * information contained in those files.
 * A "transformer" can be specified that will allow a configuration to
 * be adjusted in any way just after it was read and before it will be
 * returned, merged or otherwise used.
 * 
 * Several static helper functions exist that implement several of Ceylon's
 * configuration lookup strategies.
 * 
 * @author Tako Schotanus ([email protected])
 */
public class ConfigFinder {
    private String configName;
    private String systemPropertyOverride;
    private ConfigTransformer transformer;
    
    public static interface ConfigTransformer {
        CeylonConfig transform(File file, CeylonConfig config);
    }
    
    private static final ConfigTransformer NOOP = new ConfigTransformer() {
        @Override
        public CeylonConfig transform(File file, CeylonConfig config) {
            return config;
        }
    };
    
    /**
     * @param configName The name of the configuration file
     * @param systemPropertyOverride The name of the system property that
     * can be used to override the location of the configuration file
     * (can be 'null' if this feature is not required)
     */
    public ConfigFinder(String configName, String systemPropertyOverride) {
        this(configName, systemPropertyOverride, NOOP);
    }
    
    /**
     * @param configName The name of the configuration file
     * @param systemPropertyOverride The name of the system property that
     * can be used to override the location of the configuration file
     * (can be 'null' if this feature is not required)
     * @param transformer The transformer to use just after reading
     * a configuration
     */
    public ConfigFinder(String configName, String systemPropertyOverride, ConfigTransformer transformer) {
        this.configName = configName;
        this.systemPropertyOverride = systemPropertyOverride;
        this.transformer = transformer;
    }
    
    /**
     * Returns the configuration using the default lookup strategy in reverse,
     * which is: first the system configuration, then the user's, and then in
     * reverse order going from the localDir folder up the file system
     * hierarchy all the configuration files found in any .ceylon
     * subfolders that exist. Values from later files override earlier ones.
     * 
     * @param localDir The local folder from which to start
     * @return The configuration from all the files combined
     */
    public CeylonConfig loadDefaultConfig(File localDir) {
        CeylonConfig config = new CeylonConfig();
        try {
            CeylonConfig system = loadSystemConfig();
            merge(config, system);
        } catch (IOException e) {
            // Just ignore any errors
        }
        try {
            CeylonConfig user = loadUserConfig();
            merge(config, user);
        } catch (IOException e) {
            // Just ignore any errors
        }
        try {
            CeylonConfig local = loadLocalConfig(localDir);
            merge(config, local);
        } catch (IOException e) {
            // Just ignore any errors
        }
        CeylonConfig local = loadConfigFromProperties();
        merge(config, local);
        return config;
    }

    /**
     * Returns the configuration using the default lookup strategy which is:
     * going from the localDir folder up the file system hierarchy any
     * configuration file found in any .ceylon subfolder that exists.
     * If no file was found it will then look in the user's Ceylon folder
     * and finally the system's.
     * 
     * @param localDir The local folder from which to start
     * @return The configuration from the first file found
     */
    public CeylonConfig loadFirstConfig(File localDir) {
        try {
            File configFile = findLocalConfig(localDir);
            if (configFile != null) {
                CeylonConfig localConfig = loadConfigFromFile(configFile);
                return localConfig;
            }
        } catch (IOException e) {
            // Just ignore any errors
        }
        try {
            CeylonConfig user = loadUserConfig();
            return user;
        } catch (IOException e) {
            // Just ignore any errors
        }
        try {
            CeylonConfig system = loadSystemConfig();
            return system;
        } catch (IOException e) {
            // Just ignore any errors
        }
        CeylonConfig config = new CeylonConfig();
        return config;
    }
    
    /**
     * Returns the location for the system configuration file
     * @return File pointing to the system configuration file
     */
    public File findSystemConfig() throws IOException {
        File configDir = FileUtil.getSystemConfigDir();
        if (configDir != null) {
            return new File(configDir, configName);
        } else {
            return null;
        }
    }
    
    /**
     * Returns the system configuration. Depending on the operating system this is
     * normally "/etc/ceylon/{configName}" or "%ALLUSERSPROFILE%/ceylon/{configName}".
     * @return CeylonConfig object containing the system configuration.
     * If the file was not found the configuration will contain no values.
     * @throws IOException Either actual file-related IO exceptions or
     * InvalidPropertiesFormatException when problems with the file format
     * are detected
     */
    public CeylonConfig loadSystemConfig() throws IOException {
        File configFile = findSystemConfig();
        if (configFile != null) {
            return loadConfigFromFile(configFile);
        } else {
            return new CeylonConfig();
        }
    }
    
    /**
     * Returns the location for the user configuration file.
     * This is normally "~/.ceylon/{configName}" but can be overridden by the
     * system property as optionally passed into the constructor.
     * @return File pointing to the user configuration file
     */
    public File findUserConfig() throws IOException {
        File configFile;
        String configFilename = null;
        if (systemPropertyOverride != null) {
            configFilename = System.getProperty(systemPropertyOverride);
        }
        if (configFilename != null) {
            configFile = new File(configFilename);
        } else {
            configFile = new File(new File(System.getProperty("user.home"), Constants.CEYLON_CONFIG_DIR), configName);
        }
        return configFile;
    }
    
    /**
     * Returns the user configuration
     * @return CeylonConfig object containing the user configuration.
     * If the file was not found the configuration will contain no values.
     * @throws IOException Either actual file-related IO exceptions or
     * InvalidPropertiesFormatException when problems with the file format
     * are detected
     */
    public CeylonConfig loadUserConfig() throws IOException {
        File configFile = findUserConfig();
        return loadConfigFromFile(configFile);
    }
    
    /**
     * Returns the location for the local configuration file.
     * Ceylon will look for "./.ceylon/{configName}".
     * @return File pointing to the user configuration file
     * or "null" of no such file was found.
     */
    public File findLocalConfig(File dir) throws IOException {
        if (dir != null) {
            File userConfig1 = (new File(FileUtil.getDefaultUserDir(), configName)).getCanonicalFile();
            File userConfig2 = (new File(FileUtil.getUserDir(), configName)).getCanonicalFile();
            dir = dir.getCanonicalFile();
            while (dir != null) {
                File configFile = new File(new File(dir, Constants.CEYLON_CONFIG_DIR), configName);
                if (configFile.equals(userConfig1) || configFile.equals(userConfig2)) {
                    // We stop if we reach $HOME/.ceylon/{configName} or whatever is defined by -Dceylon.user.config
                    break;
                }
                if (configFile.isFile()) {
                    return configFile;
                }
                dir = dir.getParentFile();
            }
        }
        // We didn't find any local config file
        return null;
    }
    
    /**
     * Returns the local configuration. This is done by recursively going
     * up the file system hierachy starting with the directory passed to
     * the method. In each folder Ceylon will look if a local configuration
     * file exists ("./.ceylon/{configName}"). When reaching the root of the
     * file system all configurations will be applied in reverse order
     * (from "shallowest", closest to root, to "deepest") merging all
     * configurations found into a single result.
     * @return CeylonConfig object containing the merged configuration.
     * If the file was not found the configuration will contain no values.
     * @throws IOException Either actual file-related IO exceptions or
     * InvalidPropertiesFormatException when problems with the file format
     * are detected
     */
    public CeylonConfig loadLocalConfig(File dir) throws IOException {
        File configFile = findLocalConfig(dir);
        if (configFile != null) {
            CeylonConfig parentConfig = loadLocalConfig(dir.getCanonicalFile().getParentFile());
            CeylonConfig localConfig = loadConfigFromFile(configFile);
            return merge(parentConfig, localConfig);
        } else {
            // No config file, just return an empty CeylonConfig
            return new CeylonConfig();
        }
    }
    
    /**
     * Returns the configuration contained in the given file
     * @param configFile The file to read
     * @return CeylonConfig object containing the requested configuration.
     * If the file was not found the configuration will contain no values.
     * @throws IOException Either actual file-related IO exceptions or
     * InvalidPropertiesFormatException when problems with the file format
     * are detected
     */
    public CeylonConfig loadConfigFromFile(File configFile) throws IOException {
        return transformer.transform(configFile, (new ConfigParser(configFile)).parse(true));
    }
    
    /**
     * Returns the configuration contained in the given file but NO variable
     * substitution or other transformations will be performed
     * @param configFile The file to read
     * @return CeylonConfig object containing the requested configuration.
     * If the file was not found the configuration will contain no values.
     * @throws IOException Either actual file-related IO exceptions or
     * InvalidPropertiesFormatException when problems with the file format
     * are detected
     */
    public CeylonConfig loadOriginalConfigFromFile(File configFile) throws IOException {
        return (new ConfigParser(configFile)).parse(false);
    }
    
    /**
     * Returns the configuration contained in the given input stream.
     * If the "currentDir" parameter is given variable substitution will
     * occur for the values in the stream, specifically occurrences of
     * ${DIR} will be replaced by the path pointed to by the parameter.
     * If the parameter is "null" no substitutions will occur.
     * @param stream The InputStream to read from
     * @param currentDir The folder to use for ${DIR} substitutions or null
     * if no such substitutions should be performed
     * @return CeylonConfig object containing the requested configuration
     * @throws IOException Either actual file-related IO exceptions or
     * InvalidPropertiesFormatException when problems with the file format
     * are detected
     */
    public CeylonConfig loadConfigFromStream(InputStream stream, File currentDir) throws IOException {
        return transformer.transform(null, (new ConfigParser(stream, currentDir)).parse(currentDir != null));
    }
    
    /**
     * Returns a configuration initialized with the values encountered
     * in the System properties. Values with the name "ceylon.config.xxxx"
     * are turned into CeylonConfig options of the name "xxxx".
     * @return CeylonConfig object containing the configuration values
     * encountered in the System properties
     */
    public CeylonConfig loadConfigFromProperties() {
        CeylonConfig cfg = new CeylonConfig();
        for (String key : System.getProperties().stringPropertyNames()) {
            if (key.startsWith("ceylon.config.")) {
                String nm = key.substring(14);
                cfg.setOption(nm, System.getProperty(key));
            }
        }
        return cfg;
    }
    
    private CeylonConfig merge(CeylonConfig pool, CeylonConfig config) {
        return pool.merge(config);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy