com.qmetry.qaf.automation.core.ConfigurationManager.java Source code

Java tutorial

Introduction

Here is the source code for com.qmetry.qaf.automation.core.ConfigurationManager.java

Source

/*******************************************************************************
 * QMetry Automation Framework provides a powerful and versatile platform to
 * author
 * Automated Test Cases in Behavior Driven, Keyword Driven or Code Driven
 * approach
 * Copyright 2016 Infostretch Corporation
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or any later version.
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT
 * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE
 * You should have received a copy of the GNU General Public License along with
 * this program in the name of LICENSE.txt in the root folder of the
 * distribution. If not, see https://opensource.org/licenses/gpl-3.0.html
 * See the NOTICE.TXT file in root folder of this source files distribution
 * for additional information regarding copyright ownership and licenses
 * of other open source software / files used by QMetry Automation Framework.
 * For any inquiry or need additional information, please contact
 * support-qaf@infostretch.com
 *******************************************************************************/

package com.qmetry.qaf.automation.core;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

import org.apache.commons.configuration.AbstractConfiguration;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.event.ConfigurationEvent;
import org.apache.commons.configuration.event.ConfigurationListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.impl.LogFactoryImpl;
import org.hamcrest.Matchers;

import com.qmetry.qaf.automation.keys.ApplicationProperties;
import com.qmetry.qaf.automation.step.JavaStepFinder;
import com.qmetry.qaf.automation.step.TestStep;
import com.qmetry.qaf.automation.step.client.ScenarioFactory;
import com.qmetry.qaf.automation.step.client.csv.KwdTestFactory;
import com.qmetry.qaf.automation.step.client.excel.ExcelTestFactory;
import com.qmetry.qaf.automation.step.client.text.BDDTestFactory;
import com.qmetry.qaf.automation.util.FileUtil;
import com.qmetry.qaf.automation.util.PropertyUtil;
import com.qmetry.qaf.automation.util.StringComparator;
import com.qmetry.qaf.automation.util.StringMatcher;
import com.qmetry.qaf.automation.util.StringUtil;

/**
 * Configuration manager class. Singleton with early initialization.
 * <p>
 * This class loads file provided by system property
 * <code>application.properties.file</code> (Default value is
 * "resources/application.properties"). Also loads all property files form
 * <code>test.props.dir</code>(default value is "resources") if
 * <code>resources.load.subdirs</code> flag is 1.
 * <p>
 * To access any property value within automation, use following way
 * {@link PropertyUtil} props={@link #ConfigurationManager}.
 * {@link #getInstance()}.{@link#getApplicationProperties()};<br>
 * String sval = props.{@link PropertyUtil#getPropertyValue(String)}
 * 
 * @author chirag
 */
public class ConfigurationManager {
    // early initialization
    static final Log log = LogFactoryImpl.getLog(ConfigurationManager.class);
    private static final ConfigurationManager INSTANCE = new ConfigurationManager();

    /**
     * Private constructor, prevents instantiation from other classes
     */
    private ConfigurationManager() {
        AbstractConfiguration.setDefaultListDelimiter(';');
    }

    public static ConfigurationManager getInstance() {
        return INSTANCE;
    }

    private static InheritableThreadLocal<PropertyUtil> LocalProps = new InheritableThreadLocal<PropertyUtil>() {
        @Override
        protected PropertyUtil initialValue() {
            PropertyUtil p = new PropertyUtil(
                    System.getProperty("application.properties.file", "resources/application.properties"));
            p.setProperty("isfw.build.info", getBuildInfo());
            File prjDir = new File(".").getAbsoluteFile().getParentFile();
            p.setProperty("project.path", prjDir.getAbsolutePath());
            if (!p.containsKey("project.name"))
                p.setProperty("project.name", prjDir.getName());

            log.info("ISFW build info: " + p.getProperty("isfw.build.info"));
            String[] resources = p.getStringArray("env.resources", "resources");
            for (String resource : resources) {
                addBundle(p, resource);

            }
            ConfigurationListener cl = new PropertyConfigurationListener();
            p.addConfigurationListener(cl);
            return p;
        }

        @Override
        protected PropertyUtil childValue(PropertyUtil parentValue) {
            PropertyUtil cp = new PropertyUtil(parentValue);
            ConfigurationListener cl = new PropertyConfigurationListener();
            cp.addConfigurationListener(cl);
            return cp;
        }

    };

    /**
     * To add local resources.
     * 
     * @param fileOrDir
     */
    public static void addBundle(String fileOrDir) {
        ConfigurationManager.addBundle(getBundle(), fileOrDir);
    }

    /**
     * @param p
     * @param fileOrDir
     */
    private static void addBundle(PropertyUtil p, String fileOrDir) {
        String localResources = p.getString("local.reasources", p.getString("env.local.resources", "resources"));
        fileOrDir = p.getSubstitutor().replace(fileOrDir);
        File resourceFile = new File(fileOrDir);
        String[] locals = p.getStringArray(ApplicationProperties.LOAD_LOCALES.key);
        /**
         * will reload existing properties value(if any) if the last loaded
         * dir/file is not the current one. case: suit-1 default, suit-2 :
         * s2-local, suit-3: default Here after suit-2 you need to reload
         * default.
         */
        if (!localResources.equalsIgnoreCase(resourceFile.getAbsolutePath())) {
            p.addProperty("local.reasources", resourceFile.getAbsolutePath());
            if (resourceFile.exists()) {
                if (resourceFile.isDirectory()) {
                    boolean loadSubDirs = p.getBoolean("resources.load.subdirs", true);
                    File[] propFiles = FileUtil.listFilesAsArray(resourceFile, ".properties",
                            StringComparator.Suffix, loadSubDirs);
                    log.info("Resource dir: " + resourceFile.getAbsolutePath() + ". Found property files to load: "
                            + propFiles.length);
                    File[] locFiles = FileUtil.listFilesAsArray(resourceFile, ".loc", StringComparator.Suffix,
                            loadSubDirs);
                    File[] wscFiles = FileUtil.listFilesAsArray(resourceFile, ".wsc", StringComparator.Suffix,
                            loadSubDirs);
                    PropertyUtil p1 = new PropertyUtil();
                    p1.load(propFiles);
                    p1.load(locFiles);
                    p1.load(wscFiles);
                    p.copy(p1);

                    propFiles = FileUtil.listFilesAsArray(resourceFile, ".xml", StringComparator.Suffix,
                            loadSubDirs);
                    log.info("Resource dir: " + resourceFile.getAbsolutePath() + ". Found property files to load: "
                            + propFiles.length);

                    p1 = new PropertyUtil();
                    p1.load(propFiles);
                    p.copy(p1);

                } else {
                    try {
                        if (fileOrDir.endsWith(".properties") || fileOrDir.endsWith(".xml")
                                || fileOrDir.endsWith(".loc") || fileOrDir.endsWith(".wsc")) {
                            p.load(new File[] { resourceFile });
                        }
                    } catch (Exception e) {
                        log.error("Unable to load " + resourceFile.getAbsolutePath() + "!", e);
                    }
                }
                // add locals if any
                if (null != locals && locals.length > 0 && (locals.length == 1
                        || StringUtil.isBlank(p.getString(ApplicationProperties.DEFAULT_LOCALE.key, "")))) {
                    p.setProperty(ApplicationProperties.DEFAULT_LOCALE.key, locals[0]);
                }
                for (String local : locals) {
                    log.info("loading local: " + local);
                    addLocal(p, local, fileOrDir);
                }

            } else {
                log.error(resourceFile.getAbsolutePath() + " not exist!");
            }
        }
    }

    private static void addLocal(PropertyUtil p, String local, String fileOrDir) {
        String defaultLocal = p.getString(ApplicationProperties.DEFAULT_LOCALE.key, "");//
        File resourceFile = new File(fileOrDir);
        /**
         * will reload existing properties value(if any) if the last loaded
         * dir/file is not the current one. case: suit-1 default, suit-2 :
         * s2-local, suit-3: default Here after suit-2 you need to reload
         * default.
         */
        boolean loadSubDirs = p.getBoolean("resources.load.subdirs", true);

        if (resourceFile.exists()) {
            PropertyUtil p1 = new PropertyUtil();
            p1.setEncoding(p.getString(ApplicationProperties.LOCALE_CHAR_ENCODING.key, "UTF-8"));
            if (resourceFile.isDirectory()) {
                File[] propFiles = FileUtil.listFilesAsArray(resourceFile, "." + local, StringComparator.Suffix,
                        loadSubDirs);
                p1.load(propFiles);

            } else {
                try {
                    if (fileOrDir.endsWith(local)) {
                        p1.load(fileOrDir);
                    }
                } catch (Exception e) {
                    log.error("Unable to load " + resourceFile.getAbsolutePath() + "!", e);
                }
            }
            if (local.equalsIgnoreCase(defaultLocal)) {
                p.copy(p1);
            } else {
                Iterator<?> keyIter = p1.getKeys();
                Configuration localSet = p.subset(local);
                while (keyIter.hasNext()) {
                    String key = (String) keyIter.next();
                    localSet.addProperty(key, p1.getObject(key));
                }
            }

        } else {
            log.error(resourceFile.getAbsolutePath() + " not exist!");
        }
    }

    public static void addAll(Map<String, String> props) {
        ConfigurationManager.getBundle().addAll(props);
    }

    public static PropertyUtil getBundle() {
        return ConfigurationManager.LocalProps.get();
    }

    private static Map<String, String> getBuildInfo() {
        Manifest manifest = null;
        Map<String, String> buildInfo = new HashMap<String, String>();
        JarFile jar = null;
        try {
            URL url = ConfigurationManager.class.getProtectionDomain().getCodeSource().getLocation();
            File file = new File(url.toURI());
            jar = new JarFile(file);
            manifest = jar.getManifest();
        } catch (NullPointerException ignored) {
        } catch (URISyntaxException ignored) {
        } catch (IOException ignored) {
        } catch (IllegalArgumentException ignored) {
        } finally {
            if (null != jar)
                try {
                    jar.close();
                } catch (IOException e) {
                    log.warn(e.getMessage());
                }
        }

        if (manifest == null) {
            return buildInfo;
        }

        try {
            Attributes attributes = manifest.getAttributes("Build-Info");
            Set<Entry<Object, Object>> entries = attributes.entrySet();
            for (Entry<Object, Object> e : entries) {
                buildInfo.put(String.valueOf(e.getKey()), String.valueOf(e.getValue()));
            }
        } catch (NullPointerException e) {
            // Fall through
        }

        return buildInfo;
    }

    /**
     * Get test-step mapping for current configuration
     * 
     * @return
     */
    @SuppressWarnings("unchecked")
    public static Map<String, TestStep> getStepMapping() {
        if (!ConfigurationManager.getBundle().containsKey("teststep.mapping")) {
            ConfigurationManager.getBundle().addProperty("teststep.mapping", JavaStepFinder.getAllJavaSteps());
            if (ConfigurationManager.getBundle().containsKey(ApplicationProperties.STEP_PROVIDER_PKG.key)) {
                for (String pkg : ConfigurationManager.getBundle()
                        .getStringArray(ApplicationProperties.STEP_PROVIDER_PKG.key)) {
                    for (ScenarioFactory factory : getStepFactories()) {
                        factory.process(pkg.replaceAll("\\.", "/"));
                    }
                }
            }
        }
        return (Map<String, TestStep>) ConfigurationManager.getBundle().getObject("teststep.mapping");
    }

    private static ScenarioFactory[] getStepFactories() {
        return new ScenarioFactory[] { new BDDTestFactory(Arrays.asList("bdl")),
                new KwdTestFactory(Arrays.asList("kwl")), new ExcelTestFactory() };
    }

    private static class PropertyConfigurationListener implements ConfigurationListener {
        String oldValue;

        @SuppressWarnings("unchecked")
        @Override
        public void configurationChanged(ConfigurationEvent event) {

            if ((event.getType() == AbstractConfiguration.EVENT_CLEAR_PROPERTY
                    || event.getType() == AbstractConfiguration.EVENT_SET_PROPERTY) && event.isBeforeUpdate()) {
                oldValue = String.format("%s", getBundle().getObject(event.getPropertyName()));
            }

            if ((event.getType() == AbstractConfiguration.EVENT_ADD_PROPERTY
                    || event.getType() == AbstractConfiguration.EVENT_SET_PROPERTY) && !event.isBeforeUpdate()) {
                String key = event.getPropertyName();
                Object value = event.getPropertyValue();
                if (null != oldValue && Matchers.equalTo(oldValue).matches(value)) {
                    // do nothing
                    return;
                }

                // driver reset
                if (key.equalsIgnoreCase(ApplicationProperties.DRIVER_NAME.key)
                        // single capability or set of capabilities change
                        || StringMatcher.containsIgnoringCase(".capabilit").match(key)
                        || key.equalsIgnoreCase(ApplicationProperties.REMOTE_SERVER.key)
                        || key.equalsIgnoreCase(ApplicationProperties.REMOTE_PORT.key)) {
                    TestBaseProvider.instance().get().tearDown();
                    if (key.equalsIgnoreCase(ApplicationProperties.DRIVER_NAME.key)) {
                        TestBaseProvider.instance().get().setDriver((String) value);
                    }
                }
                String[] bundles = null;

                // Resource loading
                if (key.equalsIgnoreCase("env.resources")) {

                    if (event.getPropertyValue() instanceof ArrayList<?>) {
                        ArrayList<String> bundlesArray = ((ArrayList<String>) event.getPropertyValue());
                        bundles = bundlesArray.toArray(new String[bundlesArray.size()]);
                    } else {
                        String resourcesBundle = (String) value;
                        if (StringUtil.isNotBlank(resourcesBundle))
                            bundles = resourcesBundle.split(String.valueOf(PropertyUtil.getDefaultListDelimiter()));
                    }
                    if (null != bundles && bundles.length > 0) {
                        for (String res : bundles) {
                            log.info("Adding resources from: " + res);
                            ConfigurationManager.addBundle(res);
                        }
                    }
                }
                // Locale loading
                if (key.equalsIgnoreCase(ApplicationProperties.DEFAULT_LOCALE.key)) {
                    String[] resources = getBundle().getStringArray("env.resources", "resources");
                    for (String resource : resources) {
                        String fileOrDir = getBundle().getSubstitutor().replace(resource);
                        addLocal(getBundle(), (String) event.getPropertyValue(), fileOrDir);
                    }
                }
                // step provider package re-load
                if (key.equalsIgnoreCase(ApplicationProperties.STEP_PROVIDER_PKG.key)) {

                    // has loaded steps and adding more or override java
                    // steps....
                    // for example suite level parameter has common steps and
                    // test level parameter has test specific steps
                    if (ConfigurationManager.getBundle().containsKey("teststep.mapping")) {
                        ConfigurationManager.getStepMapping().putAll(JavaStepFinder.getAllJavaSteps());

                        for (ScenarioFactory factory : getStepFactories()) {

                            if (event.getPropertyValue() instanceof ArrayList<?>) {
                                ArrayList<String> bundlesArray = ((ArrayList<String>) event.getPropertyValue());
                                bundles = bundlesArray.toArray(new String[bundlesArray.size()]);
                                for (String pkg : bundlesArray) {
                                    factory.process(pkg.replaceAll("\\.", "/"));
                                }
                            } else {
                                String resourcesBundle = (String) value;
                                if (StringUtil.isNotBlank(resourcesBundle)) {
                                    factory.process(resourcesBundle.replaceAll("\\.", "/"));
                                }
                            }
                        }
                    }
                }
            }

        }
    }

}