com.redhat.ceylon.common.config.ConfigFinder Maven / Gradle / Ivy
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