com.redhat.rhn.common.conf.Config.java Source code

Java tutorial

Introduction

Here is the source code for com.redhat.rhn.common.conf.Config.java

Source

/**
 * Copyright (c) 2009--2014 Red Hat, Inc.
 *
 * This software is licensed to you under the GNU General Public License,
 * version 2 (GPLv2). There is NO WARRANTY for this software, express or
 * implied, including the implied warranties of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
 * along with this software; if not, see
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
 *
 * Red Hat trademarks are not licensed under GPLv2. No permission is
 * granted to use or replicate Red Hat trademarks that are incorporated
 * in this software or its documentation.
 */

package com.redhat.rhn.common.conf;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.TreeSet;

/**
 * The Config class acts as an abstraction layer between our configuration
 * system, and the actual implementation. The basic idea is that there is a
 * global config, but you can instantiate one of your own if you want. This
 * layer insulates us from changing the underlying implementation.
 * <p>
 * Config files are properties, with /usr/share/rhn/config-defaults/rhn.conf
 * setting defaults that can be overridden by /etc/rhn/rhn.conf.
 *
 * @version $Rev$
 */
public class Config {

    private static Logger logger = Logger.getLogger(Config.class);

    //
    // Location of config files
    //

    /**
     * The default directory in which to look for config files
     */
    public static final String DEFAULT_CONF_DIR = "/etc/rhn";

    /**
     * The directory in which to look for default config values
     */
    public static final String DEFAULT_DEFAULT_CONF_DIR = "/usr/share/rhn/config-defaults";

    /**
     * The system property containing the configuration directory.
     * If the property is not set, config files are read
     * from {@link #DEFAULT_CONF_DIR}
     */
    private static final String CONF_DIR_PROPERTY = "rhn.config.dir";

    /**
     * List of values that are considered true, ignoring case.
     */
    private static final String[] TRUE_VALUES = { "1", "y", "true", "yes", "on" };

    /**
     * array of prefix in the order they should be search
     * if the given lookup string is without a namespace.
     */
    private final String[] prefixOrder = new String[] { "web", "server" };
    private static Config singletonConfig = null;
    /** hash of configuration properties */
    private final Properties configValues = new Properties();
    /** set of configuration file names */
    private final TreeSet<File> fileList = new TreeSet<File>(new Comparator<File>() {

        /** {inheritDoc} */
        public int compare(File f1, File f2) {
            // Need to make sure we read the child namespace before the base
            // namespace.  To do that, we sort the list in reverse order based
            // on the length of the file name.  If two filenames have the same
            // length, then we need to do a lexigraphical comparison to make
            // sure that the filenames themselves are different.

            int lenDif = f2.getAbsolutePath().length() - f1.getAbsolutePath().length();

            if (lenDif != 0) {
                return lenDif;
            }
            return f2.compareTo(f1);
        }
    });

    /**
     * public constructor. Rereads config entries every time it is called.
     *
     * @throws ConfigException error from the Configuration layers. the jakarta
     * commons conf system just throws Exception, which makes it hard to react.
     * sometioes it is an IOExceptions, sometimes a SAXParserException,
     * sometimes a VindictiveException. so we just turn them into our own
     * exception type and toss them up. as we discover ones we might
     * meaningfully want to react to, we can specilize ConfigException and catch
     * those
     */
    public Config() throws ConfigException {
        addPath(DEFAULT_DEFAULT_CONF_DIR);
        addPath(getDefaultConfigFilePath());
        parseFiles();
    }

    /**
     * Add a path to the config object for parsing
     * @param path The path to add
     */
    public void addPath(String path) {
        getFiles(path);
    }

    /**
     * static method to get the singleton Config option
     *
     * @return the config option
     */
    public static synchronized Config get() {
        if (singletonConfig == null) {
            singletonConfig = new Config();
        }
        return singletonConfig;
    }

    private static String getDefaultConfigDir() {
        String confDir = System.getProperty(CONF_DIR_PROPERTY);

        if (StringUtils.isBlank(confDir)) {
            confDir = DEFAULT_CONF_DIR;
        }
        return confDir;
    }

    /**
     * Get the path to the rhn.conf file we use.
     *
     * @return String path.
     */
    public static String getDefaultConfigFilePath() {
        return getDefaultConfigDir() + "/rhn.conf";
    }

    /**
     * Get the configuration entry for the given string name.  If the value
     * is null, then return the given defValue.  defValue can be null as well.
     * @param name name of property
     * @param defValue default value for property if it is null.
     * @return the value of the property with the given name, or defValue.
     */
    public String getString(String name, String defValue) {
        String ret = getString(name);
        if (ret == null) {
            if (logger.isDebugEnabled()) {
                logger.debug("getString() - returning default value");
            }
            ret = defValue;
        }
        return ret;
    }

    /**
     * @param name Key to check for
     * @return true if the config contains key
     */
    public boolean containsKey(String name) {
        return configValues.containsKey(name);
    }

    /**
     * get the config entry for string s
     *
     * @param value string to get the value of
     * @return the value
     */
    public String getString(String value) {
        if (logger.isDebugEnabled()) {
            logger.debug("getString() -     getString() called with: " + value);
        }
        if (value == null) {
            return null;
        }

        int lastDot = value.lastIndexOf('.');
        String ns = "";
        String property = value;
        if (lastDot > 0) {
            property = value.substring(lastDot + 1);
            ns = value.substring(0, lastDot);
        }
        if (logger.isDebugEnabled()) {
            logger.debug("getString() -     getString() -> Getting property: " + property);
        }
        String result = configValues.getProperty(property);
        if (logger.isDebugEnabled()) {
            logger.debug("getString() -     getString() -> result: " + result);
        }
        if (result == null) {
            if (!"".equals(ns)) {
                result = configValues.getProperty(ns + "." + property);
            } else {
                for (int i = 0; i < prefixOrder.length; i++) {
                    result = configValues.getProperty(prefixOrder[i] + "." + property);
                    if (result != null) {
                        break;
                    }
                }
            }
        }
        if (logger.isDebugEnabled()) {
            logger.debug("getString() -     getString() -> returning: " + result);
        }

        if (result == null || result.equals("")) {
            return null;
        }

        return StringUtils.trim(result);
    }

    /**
     * get the config entry for string s
     *
     * @param s string to get the value of
     * @return the value
     */
    public int getInt(String s) {
        return getInt(s, 0);
    }

    /**
     * get the config entry for string s, if no value is found
     * return the defaultValue specified.
     *
     * @param s string to get the value of
     * @param defaultValue Default value if entry is not found.
     * @return the value
     */
    public int getInt(String s, int defaultValue) {
        Integer val = getInteger(s);
        if (val == null) {
            return defaultValue;
        }
        return val.intValue();
    }

    /**
     * get the config entry for string s
     *
     * @param s string to get the value of
     * @return the value
     */
    public Integer getInteger(String s) {
        String val = getString(s);
        if (val == null) {
            return null;
        }
        return new Integer(val);
    }

    /**
     * Parses a comma-delimited list of values as a java.util.List
     * @param name config entry name
     * @return instance of java.util.List populated with config values
     */
    public List<String> getList(String name) {
        List<String> retval = new LinkedList<String>();
        String[] vals = getStringArray(name);
        if (vals != null) {
            retval.addAll(Arrays.asList(vals));
        }
        return retval;
    }

    /**
     * get the config entry for string s
     *
     * @param s string to get the value of
     * @return the value
     */
    public String[] getStringArray(String s) {
        if (s == null) {
            return null;
        }
        String value = getString(s);

        if (value == null) {
            return null;
        }

        return value.split(",");
    }

    /**
     * get the config entry for string name
     *
     * @param name string to set the value of
     * @param value new value
     * @return the previous value of the property
     */
    public String setString(String name, String value) {
        return (String) configValues.setProperty(name, value);
    }

    /**
     * remove the config entry for key
     * @param name key to remove
     */
    public void remove(String name) {
        configValues.remove(name);
    }

    /**
     * get the config entry for string s
     *
     * @param s string to get the value of
     * @return the value
     */
    public boolean getBoolean(String s) {
        String value = getString(s);
        if (logger.isDebugEnabled()) {
            logger.debug("getBoolean() - " + s + " is : " + value);
        }
        if (value == null) {
            return false;
        }

        //need to check the possible true values
        // tried to use BooleanUtils, but that didn't
        // get the job done for an integer as a String.

        for (int i = 0; i < TRUE_VALUES.length; i++) {
            if (TRUE_VALUES[i].equalsIgnoreCase(value)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("getBoolean() - Returning true: " + value);
                }
                return true;
            }
        }

        return false;
    }

    /**
     * set the config entry for string name
     * @param s string to set the value of
     * @param b new value
     */
    public void setBoolean(String s, String b) {
        // need to check the possible true values
        // tried to use BooleanUtils, but that didn't
        // get the job done for an integer as a String.
        for (int i = 0; i < TRUE_VALUES.length; i++) {
            if (TRUE_VALUES[i].equalsIgnoreCase(b)) {
                configValues.setProperty(s, "1");

                // get out we're done here
                return;
            }
        }
        configValues.setProperty(s, "0");
    }

    private void getFiles(String path) {
        File f = new File(path);

        if (f.isDirectory()) {
            // bugzilla: 154517; only add items that end in .conf
            File[] files = f.listFiles();
            if (files == null) {
                logger.error("Unable to list files in path : " + path);
                return;
            }
            for (int i = 0; i < files.length; i++) {
                if (files[i].getName().endsWith((".conf"))) {
                    fileList.add(files[i]);
                }
            }
        } else {
            fileList.add(f);
        }
    }

    private String makeNamespace(File f) {
        String ns = f.getName();

        // This is really hokey, but it works. Basically, rhn.conf doesn't
        // match the standard rhn_foo.conf convention. So, to create the
        // namespace, we first special case rhn.*
        if (ns.startsWith("rhn.")) {
            return "";
        }

        ns = ns.replaceFirst("rhn_", "");
        int lastDotindex = ns.lastIndexOf('.');
        if (lastDotindex != -1) {
            ns = ns.substring(0, ns.lastIndexOf('.'));
        }
        ns = ns.replaceAll("_", ".");
        return ns;
    }

    /**
     * Parse all of the added files.
     */
    public void parseFiles() {
        for (Iterator<File> i = fileList.iterator(); i.hasNext();) {
            File curr = i.next();

            Properties props = new Properties();
            try {
                props.load(new InputStreamReader(new FileInputStream(curr), "UTF-8"));
            } catch (IOException e) {
                logger.error("Could not parse file " + curr, e);
            }
            String ns = makeNamespace(curr);
            logger.debug("Adding namespace: " + ns + " for file: " + curr.getAbsolutePath());

            // loop through all of the config values in the properties file
            // making sure the prefix is there.
            Properties newProps = new Properties();
            for (Iterator j = props.keySet().iterator(); j.hasNext();) {
                String key = (String) j.next();
                String newKey = key;
                if (!key.startsWith(ns)) {
                    newKey = ns + "." + key;
                }
                logger.debug("Adding: " + newKey + ": " + props.getProperty(key));
                newProps.put(newKey, props.getProperty(key));
            }
            configValues.putAll(newProps);
        }
    }

    /**
     * Returns a subset of the properties for the given namespace. This is
     * not a particularly fast method and should be used only at startup or
     * some other discreet time.  Repeated calls to this method are guaranteed
     * to be slow.
     * @param namespace Namespace of properties to be returned.
     * @return subset of the properties that begin with the given namespace.
     */
    public Properties getNamespaceProperties(String namespace) {
        Properties prop = new Properties();
        for (Iterator i = configValues.keySet().iterator(); i.hasNext();) {
            String key = (String) i.next();
            if (key.startsWith(namespace)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Looking for key: [" + key + "]");
                }
                prop.put(key, configValues.getProperty(key));
            }
        }
        return prop;
    }
}