com.vmware.aurora.global.Configuration.java Source code

Java tutorial

Introduction

Here is the source code for com.vmware.aurora.global.Configuration.java

Source

/***************************************************************************
 * Copyright (c) 2012-2015 VMware, Inc. All Rights Reserved.
 * 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.vmware.aurora.global;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.URL;
import java.util.Enumeration;
import java.util.Iterator;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.ConfigurationUtils;
import org.apache.commons.configuration.ConversionException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.lang.ArrayUtils;
import org.apache.log4j.Logger;

import com.vmware.aurora.exception.AuroraException;
import com.vmware.aurora.exception.CommonException;
import com.vmware.aurora.util.AuAssert;
import com.vmware.aurora.util.StringUtil;

/**
 * <code>Configuration</code> is a util class for accessing configurations of
 * CMS. <br>
 * 
 * @since 0.4.2
 * @version 0.4.2
 * @author Gene Zhang
 */
public class Configuration {
    private static Logger logger = Logger.getLogger(Configuration.class);
    private static String configFileName;
    private static PropertiesConfiguration config = init();
    private static PropertiesConfiguration serengetiCfg;
    private static PropertiesConfiguration vcCfg;
    private static String storedCmsInstanceId;
    private static final String NGC_PROP_FILE = "ngc_registrar.properties";
    private static PropertiesConfiguration ngcCfg;

    /**
     * 
     * @return a memory view of all properties inside serengeti.properties and vc.properties
     */
    private static PropertiesConfiguration init() {
        PropertiesConfiguration config = null;

        String homeDir = System.getProperties().getProperty("serengeti.home.dir");
        String ngcConfigFile = NGC_PROP_FILE;
        if (homeDir != null && homeDir.length() > 0) {
            StringBuilder builder = new StringBuilder();
            builder.append(homeDir).append(File.separator).append("conf").append(File.separator);
            configFileName = builder.toString() + "serengeti.properties";
            ngcConfigFile = builder.toString() + NGC_PROP_FILE;
        } else {
            configFileName = "serengeti.properties";
        }

        try {
            URL url = ConfigurationUtils.locate(null, configFileName);
            logger.info("Reading properties file serengeti.properties from " + url.getPath());
            serengetiCfg = new PropertiesConfiguration();
            serengetiCfg.setEncoding("UTF-8");
            serengetiCfg.setFileName(configFileName);
            serengetiCfg.load();
            config = (PropertiesConfiguration) serengetiCfg.clone();
        } catch (ConfigurationException ex) {
            String message = "Failed to load serengeti.properties file.";
            logger.fatal(message, ex);
            throw AuroraException.APP_INIT_ERROR(ex, message);
        }

        String propertyFilePrefix = System.getProperty("PROPERTY_FILE_PREFIX", "vc");
        String propertyFileName = propertyFilePrefix + ".properties";

        try {
            logger.info("Reading properties file " + propertyFileName);
            vcCfg = new PropertiesConfiguration(propertyFileName);
            Iterator<?> keys = vcCfg.getKeys();
            while (keys.hasNext()) {
                String key = (String) keys.next();
                config.setProperty(key, vcCfg.getProperty(key));
            }
        } catch (ConfigurationException ex) {
            // error out if the configuration file is not there
            String message = "Failed to load vc.properties file.";
            logger.fatal(message, ex);
            throw AuroraException.APP_INIT_ERROR(ex, message);
        }
        // load ngc_registrar.properties
        try {
            logger.info("Reading properties file " + ngcConfigFile);
            ngcCfg = new PropertiesConfiguration(ngcConfigFile);
            ngcCfg.setEncoding("UTF-8");
            Iterator<?> keys = ngcCfg.getKeys();
            while (keys.hasNext()) {
                String key = (String) keys.next();
                config.setProperty(key, ngcCfg.getProperty(key));
            }
        } catch (ConfigurationException ex) {
            // error out if the configuration file is not there
            String message = "Failed to load file " + NGC_PROP_FILE;
            logger.fatal(message, ex);
            throw AuroraException.APP_INIT_ERROR(ex, message);
        }

        logConfig(config);
        return config;
    }

    private static void logConfig(org.apache.commons.configuration.Configuration config) {
        Iterator<?> keys = config.getKeys();
        while (keys.hasNext()) {
            String key = (String) keys.next();
            logger.debug("Config '" + key + "=" + config.getProperty(key) + "'");
        }
    }

    /**
     * 
     * Gets a property of type int. <br>
     * 
     * @param key
     *           The key of property.
     * @return The property value.
     */
    public static int getInt(String key) {
        return config.getInt(key);
    }

    /**
     * 
     * Gets a property of type int. <br>
     * 
     * @param defaultValue
     *           The default value.
     * @param key
     *           The key of property.
     * @return The property value.
     */
    public static int getInt(String key, int defaultValue) {
        try {
            return config.getInt(key, defaultValue);
        } catch (ConversionException ce) {
            logger.error(key + " in serengeti.properties is not an integer!");
        }

        return defaultValue;
    }

    /**
     * 
     * Gets a property of type bool. <br>
     * 
     * @param key
     *           The key of property.
     * @return The property value.
     */
    public static Boolean getBoolean(String key) {
        return config.getBoolean(key);
    }

    /**
     * 
     * Gets a property of type bool. <br>
     * 
     * @param defaultValue
     *           The default value.
     * @param key
     *           The key of property.
     * @return The property value.
     */
    public static Boolean getBoolean(String key, Boolean defaultValue) {
        try {
            return config.getBoolean(key, defaultValue);
        } catch (ConversionException ce) {
            logger.error(key + " in serengeti.properties is not a boolean!");
        }

        return defaultValue;
    }

    /**
     * 
     * Gets a property of type string. <br>
     * 
     * @param key
     *           The key of property.
     * @return The property value.
     */
    public static String getString(String key) {
        return config.getString(key);
    }

    /**
     * 
     * Gets a property of type string. <br>
     * 
     * @param defaultValue
     *           The default value.
     * @param key
     *           The key of property.
     * @return The property value.
     */
    public static String getString(String key, String defaultValue) {
        return config.getString(key, defaultValue);
    }

    /**
     * Gets a whitespace trimmed non-empty string property.
     * 
     * @param key
     *           The key of property.
     * @return The property value or null.
     */
    public static String getNonEmptyString(String key) {
        String s = getString(key, null);
        return StringUtil.trimNonEmpty(s);
    }

    /**
     * 
     * Gets a property of type double. <br>
     * 
     * @param key
     *           The key of property.
     * @return The property value.
     */
    public static Double getDouble(String key) {
        return config.getDouble(key);
    }

    /**
     * 
     * Gets a property of type double. <br>
     * 
     * @param defaultValue
     *           The default value.
     * @param key
     *           The key of property.
     * @return The property value.
     */
    public static Double getDouble(String key, Double defaultValue) {
        try {
            return config.getDouble(key, defaultValue);
        } catch (ConversionException ce) {
            logger.error(key + " in serengeti.properties is not a double!");
        }

        return defaultValue;
    }

    /**
     * 
     * Gets a property of type Long. <br>
     * 
     * @param key
     *           The key of property.
     * @return The property value.
     */
    public static long getLong(String key) {
        return config.getLong(key);
    }

    /**
     * 
     * Gets a property of type Long. <br>
     * 
     * @param key
     *           The key of property.
     * @param defaultValue
     *           The default value.
     * @return The property value.
     */
    public static long getLong(String key, long defaultValue) {
        try {
            return config.getLong(key, defaultValue);
        } catch (ConversionException ce) {
            logger.error(key + " in serengeti.properties is not a long!");
        }

        return defaultValue;
    }

    /**
     * Test if a key exists
     * 
     * @param key
     *           .
     * @return true if key exists.
     */
    public static boolean containsKey(String key) {
        return config.containsKey(key);
    }

    /**
     * Return the CMS instance identifier, global to this instance of the CMS.
     * 
     * @return CMS instance identifier
     */
    public static String getCmsInstanceId() {
        /*
         * We have two sources for the instance ID: the database ("stored instance
         * id") and properties file ("bootstrap instance id"). We prefer the
         * stored instance id, but use the bootstrap one if it's not available
         * (mostly for bootstrapping, also for unit tests that don't have a
         * database).
         *
         * In normal use, during the setup process we read the bootstrap instance
         * id and store it in the database, after which we always use the stored
         * one. (They would be the same unless some disaster happens where the
         * VM gets reprovisioned from backup and the bootstrap one in the properties
         * file changes, which is why we prefer using the one we stored in the db.)
         *
         * As a further complication, for dependency reasons we want to expose the
         * instance ID from this layer, but also for dependency reasons we're unable
         * to read the DB here. So we can't read the stored instance ID ourselves;
         * we require some other layer (CmsConfig) to read it and inject it here.
         * VirtualCenterResourceManagement will copy the bootstrap instance ID to
         * the DB during setup, and also call us, and thereafter Organization will
         * call us during system initialization.
         */
        if (bootstrapMode == Configuration.BootstrapUsage.ALLOWED) {
            // In the window after we notice setup hasn't run yet and before we run
            // setup, we initialize the VC context and it's allowed to use the
            // bootstrap instance ID.
            AuAssert.check(storedCmsInstanceId == null);
            return getBootstrapInstanceId();
        }
        // Otherwise, we require that we're using the stored instance ID.
        AuAssert.check(storedCmsInstanceId != null);
        return storedCmsInstanceId;
    }

    public enum BootstrapUsage {
        DISALLOWED, ALLOWED, FINALIZED;
    }

    private static BootstrapUsage bootstrapMode = BootstrapUsage.DISALLOWED;

    /**
     * Set the CMS instance identifier which will be returned by
     * getCmsInstanceId(). Can be called only once per process during
     * initialization. This variant is used only during system setup
     * (VirtualCenterResourceManagement.initializeSystem); otherwise
     * setCmsInstanceId is preferred.
     */
    public static String approveBootstrapInstanceId(BootstrapUsage usage) {
        switch (usage) {
        case ALLOWED:
            // transition from DISALLOWED to ALLOWED
            AuAssert.check(bootstrapMode == BootstrapUsage.DISALLOWED);
            AuAssert.check(storedCmsInstanceId == null);
            bootstrapMode = usage;
            return null;
        case FINALIZED:
            // transition from ALLOWED to FINALIZED
            AuAssert.check(bootstrapMode == BootstrapUsage.ALLOWED);
            AuAssert.check(storedCmsInstanceId == null);
            setCmsInstanceId(getBootstrapInstanceId());
            bootstrapMode = usage;
            return getCmsInstanceId();
        default:
            // no other transition is legal
            AuAssert.check(false);
            return null;
        }
    }

    /**
     * Set the CMS instance identifier which will be returned by
     * getCmsInstanceId(). Can be called only once per process during
     * initialization.
     * 
     * @param id
     *           Instance ID retrieved from database.
     */
    public static void setCmsInstanceId(String id) {
        /*
         * This can be called only once per process, so the value can't change after
         * it's set. The current caller is CmsConfig.init().
         *
         * We require this be injected from an external source because we can't
         * calculate it here due to dependencies; however (also due to dependencies)
         * we want to provide access to this value from here. So we're happy to
         * store-and-forward here.
         */
        AuAssert.check(storedCmsInstanceId == null);
        storedCmsInstanceId = id;

        // sanity check
        String bootstrapId = getBootstrapInstanceId();
        if (!id.equals(bootstrapId)) {
            logger.warn("Instance ID has changed from " + bootstrapId + " to " + id);
        }
    }

    /**
     * Generate the instance ID from the stored moref to the CMS VM.
     * 
     * @return Bootstrap instance ID.
     */
    private static String getBootstrapInstanceId() {
        String cmsVmIdText = Configuration.getString("vim.cms_moref");
        int pos = cmsVmIdText.lastIndexOf('-');
        if (pos == -1) {
            logger.error("Unrecognized CMS VM moref Id: " + cmsVmIdText);
            throw CommonException.INTERNAL();
        }
        Long cmsVmId = Long.parseLong(cmsVmIdText.substring(pos + 1));
        return Integer.toHexString(cmsVmId.hashCode()); // enforce maximum of 8 digits
    }

    /**
     * Gets the fqdn of cms server. If it's not presented, the method tries to
     * retrieve the ip address of first network interface and reports it as the
     * fqdn.
     * 
     * @return The FQDN of CMS.
     */
    public static String getCmsFQDN() {
        String fqdn = Configuration.getString("cms.mgmtnet.fqdn");
        if (fqdn == null || fqdn.isEmpty()) {
            try {
                // try to retrieve the ip addr of eth0
                NetworkInterface net = NetworkInterface.getByName("eth0");
                Enumeration<InetAddress> addresses = net.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress addr = addresses.nextElement();
                    if (addr instanceof Inet4Address) {
                        String ip = addr.toString();
                        fqdn = ip.substring(ip.lastIndexOf("/") + 1);
                        break;
                    }
                }
            } catch (Exception e) {
                logger.info("Error in retrieving ip of eth0", e);
                throw CommonException.INTERNAL(e);
            }
        }
        return fqdn;
    }

    /**
     * Get all of values in a property as a String[] type.
     *
     * @param key
     *           The key of property.
     * @return The property value.
     */
    public static String[] getStringArray(String key) {
        return config.getStringArray(key);
    }

    /**
     * Get all of values in a property as a String[] type.
     *
     * @param key
     *           The key of property.
     * @param defautValue
     *           The default value.
     * @return The property value.
     */
    public static String[] getStringArray(String key, String[] defautValue) {
        String[] values = getStringArray(key);
        if (!ArrayUtils.isEmpty(values))
            return values;
        return defautValue;
    }

    /**
     * Get all of values in a property as a String[] type
     * and judge the legality of ThreadPoolConfig.
     * four default parameters here
     *
     *  @param key
     *           The key of property.
     * @param defautValue
     *           The default value.
     * @return The property value.
     */
    public static String[] getThreadConfig(String key, String[] defautValue) {
        String[] values = getStringArray(key, defautValue);
        if (values.length == 3)
            return values;
        return defautValue;
    }

    /**
     * Get all of values in a property as a string type.
     * 
     * @param key
     *           The key of property.
     * @param defautValue
     *           The default value.
     * @return The property value.
     */
    public static String getStrings(String key, String defautValue) {
        String[] values = config.getStringArray(key);
        if (values != null && values.length > 0) {
            StringBuffer buffer = new StringBuffer();
            for (String value : values) {
                buffer.append(value.trim()).append(",");
            }
            buffer.delete(buffer.length() - 1, buffer.length());
            return buffer.toString();
        } else {
            return defautValue;
        }
    }

    /**
     * Set the boolean value of a given key
     * 
     * @param key
     * @param value
     */
    public static void setBoolean(String key, Boolean value) {
        config.setProperty(key, value);
        if (vcCfg.containsKey(key)) {
            vcCfg.setProperty(key, value);
        } else {
            serengetiCfg.setProperty(key, value);
        }
    }

    public static void setString(String key, String value) {
        config.setProperty(key, value);
        if (vcCfg.containsKey(key)) {
            vcCfg.setProperty(key, value);
        } else {
            serengetiCfg.setProperty(key, value);
        }
    }

    public static void save() {
        OutputStream out = null;
        try {
            // we only have reqs to save serengeti.properties currently
            out = new FileOutputStream(new File(serengetiCfg.getPath()));
            serengetiCfg.save(out);
        } catch (Exception ex) {
            // error out if the configuration file is not there
            String message = "Failed to save serengeti configuration file: " + configFileName;
            logger.fatal(message, ex);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                logger.error("Failed to close file: " + configFileName + ", after save configuration.");
            }
        }
    }
}