/* * Sakuli - Testing and Monitoring-Tool for Websites and common UIs. * * Copyright 2013 - 2015 the original author or authors. * * 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 org.sakuli.utils; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.PropertiesConfiguration; import org.sakuli.datamodel.properties.SahiProxyProperties; import org.sakuli.datamodel.properties.SakuliProperties; import org.sakuli.datamodel.properties.TestSuiteProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import javax.annotation.PreDestroy; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.*; import static org.apache.commons.lang.StringUtils.isNotEmpty; /** * Overrides the default {@link PropertyPlaceholderConfigurer} to dynamically load the properties files in the {@link * TestSuiteProperties#TEST_SUITE_FOLDER} and {@link SakuliProperties#SAKULI_HOME_FOLDER}. * * @author tschneck Date: 11.05.14 */ public class SakuliPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer { public static String TEST_SUITE_FOLDER_VALUE; public static String SAKULI_HOME_FOLDER_VALUE; public static String SAHI_HOME_VALUE; public static String TEST_SUITE_BROWSER; protected boolean loadSakuliProperties = true; protected boolean loadSakuliDefaultProperties = true; protected boolean loadTestSuiteProperties = true; protected boolean writePropertiesToSahiConfig = true; private Logger logger = LoggerFactory.getLogger(this.getClass()); private Map<String, Map<String, Object>> modifiedSahiConfigProps; public SakuliPropertyPlaceholderConfigurer() { modifiedSahiConfigProps = new HashMap<>(); } @Override protected void loadProperties(Properties props) throws IOException { //load properties set by command args props.put(TestSuiteProperties.TEST_SUITE_FOLDER, TEST_SUITE_FOLDER_VALUE); props.put(SakuliProperties.SAKULI_HOME_FOLDER, SAKULI_HOME_FOLDER_VALUE); //load common sakuli properties loadSakuliDefaultProperties(props); loadSakuliProperties(props); loadTestSuiteProperties(props); //overwrite if set sahi proxy home if (isNotEmpty(SAHI_HOME_VALUE)) { props.setProperty(SahiProxyProperties.PROXY_HOME_FOLDER, SAHI_HOME_VALUE); props.setProperty(SahiProxyProperties.PROXY_CONFIG_FOLDER, SAHI_HOME_VALUE + File.separator + "userdata"); } if (isNotEmpty(TEST_SUITE_BROWSER)) { props.setProperty(TestSuiteProperties.BROWSER_NAME, TEST_SUITE_BROWSER); } modifySahiProperties(props); super.loadProperties(props); } protected void loadSakuliDefaultProperties(Properties props) { String sakuliDefaultProperties = Paths.get(SAKULI_HOME_FOLDER_VALUE + SakuliProperties.CONFIG_FOLDER_APPEDER).normalize().toAbsolutePath().toString() + SakuliProperties.SAKULI_DEFAULT_PROPERTIES_FILE_APPENDER; addPropertiesFromFile(props, sakuliDefaultProperties, loadSakuliDefaultProperties); } protected void loadSakuliProperties(Properties props) { String sakuliProperties = Paths.get(TEST_SUITE_FOLDER_VALUE).getParent().normalize().toAbsolutePath().toString() + SakuliProperties.SAKULI_PROPERTIES_FILE_APPENDER; if (Files.exists(Paths.get(sakuliProperties))) { addPropertiesFromFile(props, sakuliProperties, loadSakuliProperties); } } protected void loadTestSuiteProperties(Properties props) { String testSuitePropFile = Paths.get(TEST_SUITE_FOLDER_VALUE).normalize().toAbsolutePath().toString() + TestSuiteProperties.TEST_SUITE_PROPERTIES_FILE_APPENDER; addPropertiesFromFile(props, testSuitePropFile, loadTestSuiteProperties); } @PreDestroy public void restoreProperties() { try { for (Map.Entry<String, Map<String, Object>> entry : modifiedSahiConfigProps.entrySet()) { String propFile = entry.getKey(); logger.debug("restore properties file '{}' with properties '{}'", propFile, entry.getValue()); PropertiesConfiguration propConfig = new PropertiesConfiguration(propFile); propConfig.setAutoSave(true); for (Map.Entry<String, Object> propEntry : entry.getValue().entrySet()) { String propKey = propEntry.getKey(); if (propConfig.containsKey(propKey)) { propConfig.clearProperty(propKey); } propConfig.addProperty(propKey, propEntry.getValue()); } } } catch (ConfigurationException e) { logger.error("Error in restore sahi config properties", e); } } /** * Reads in the properties for a specific file * * @param props Properties to update * @param filePath path to readable properties file * @param active activate or deactivate the function */ protected void addPropertiesFromFile(Properties props, String filePath, boolean active) { if (active) { logger.info("read in properties from '{}'", filePath); try { PropertiesConfiguration propertiesConfiguration = new PropertiesConfiguration(filePath); Iterator<String> keyIt = propertiesConfiguration.getKeys(); while (keyIt.hasNext()) { String key = keyIt.next(); Object value = propertiesConfiguration.getProperty(key); props.put(key, value); } } catch (ConfigurationException | NullPointerException e) { throw new RuntimeException("Error by reading the property file '" + filePath + "'", e); } } } protected void modifySahiProperties(Properties props) { if (writePropertiesToSahiConfig) { String sahiConfigFolderPath = resolve(props.getProperty(SahiProxyProperties.PROXY_CONFIG_FOLDER), props); String sahiPropConfig = Paths.get(sahiConfigFolderPath + SahiProxyProperties.SAHI_PROPERTY_FILE_APPENDER).normalize().toAbsolutePath().toString(); modifyPropertiesConfiguration(sahiPropConfig, SahiProxyProperties.userdataPropertyNames, props); modifySahiProxyPortPropertiesConfiguration(sahiPropConfig, props); String sahiLogPropConfig = Paths.get(sahiConfigFolderPath + SahiProxyProperties.SAHI_LOG_PROPERTY_FILE_APPENDER).normalize().toAbsolutePath().toString(); modifyPropertiesConfiguration(sahiLogPropConfig, SahiProxyProperties.logPropertyNames, props); } } private String resolve(String string, Properties props) { if (string != null) { int i = string.indexOf("${"); if (i >= 0) { String result = string.substring(0, i); int iLast = string.indexOf("}"); String key = string.substring(i + 2, iLast); result += props.get(key) + string.substring(iLast + 1); return resolve(result, props); } } return string; } /** * writes the {@link SahiProxyProperties#PROXY_PORT} value as {@link SahiProxyProperties#SAHI_PROPERTY_PROXY_PORT_MAPPING} * property to sahiConfigPropertyFilePath! */ protected void modifySahiProxyPortPropertiesConfiguration(String sahiConfigPropertyFilePath, Properties props) { final String sahiProxyPort = props.getProperty(SahiProxyProperties.PROXY_PORT); if (sahiProxyPort != null) { try { PropertiesConfiguration propConfig = new PropertiesConfiguration(sahiConfigPropertyFilePath); propConfig.setAutoSave(true); final String sahiMappingPropertyProxyPort = SahiProxyProperties.SAHI_PROPERTY_PROXY_PORT_MAPPING; if (propConfig.containsKey(sahiMappingPropertyProxyPort)) { propConfig.clearProperty(sahiMappingPropertyProxyPort); } //remove property after the test execution, so that the installation can't break addToModifiedPropertiesMap(sahiConfigPropertyFilePath, sahiMappingPropertyProxyPort, null); propConfig.addProperty(sahiMappingPropertyProxyPort, sahiProxyPort); logger.debug("modify properties file '{}' with '{}={}'", sahiConfigPropertyFilePath, sahiMappingPropertyProxyPort, sahiProxyPort); } catch (ConfigurationException e) { logger.error("modify sahi properties went wrong", e); } } } /** * Modifies the properties file 'propFilePathToConfig' with assigned key from the resource properties. */ protected void modifyPropertiesConfiguration(String propFilePathToConfig, List<String> updateKeys, Properties resourceProps) { try { PropertiesConfiguration propConfig = new PropertiesConfiguration(propFilePathToConfig); propConfig.setAutoSave(true); Properties temProps = new Properties(); for (String propKey : updateKeys) { String resolve = resolve(resourceProps.getProperty(propKey), resourceProps); if (resolve != null) { if (propConfig.containsKey(propKey)) { addToModifiedPropertiesMap(propFilePathToConfig, propKey, propConfig.getProperty(propKey)); propConfig.clearProperty(propKey); } temProps.put(propKey, resolve); propConfig.addProperty(propKey, resolve); } } logger.debug("modify properties file '{}' with '{}'", propFilePathToConfig, temProps.toString()); } catch (ConfigurationException e) { logger.error("modify sahi properties went wrong", e); } } protected void addToModifiedPropertiesMap(String propFilePath, String propKey, Object propertyValue) { Map<String, Object> propMap = modifiedSahiConfigProps.get(propFilePath); if (propMap == null) { propMap = new HashMap<>(); } propMap.put(propKey, propertyValue); modifiedSahiConfigProps.put(propFilePath, propMap); } public boolean isLoadSakuliDefaultProperties() { return loadSakuliDefaultProperties; } public void setLoadSakuliDefaultProperties(boolean loadSakuliDefaultProperties) { this.loadSakuliDefaultProperties = loadSakuliDefaultProperties; } public boolean isLoadSakuliProperties() { return loadSakuliProperties; } public void setLoadSakuliProperties(boolean loadSakuliProperties) { this.loadSakuliProperties = loadSakuliProperties; } public boolean isLoadTestSuiteProperties() { return loadTestSuiteProperties; } public void setLoadTestSuiteProperties(boolean loadTestSuiteProperties) { this.loadTestSuiteProperties = loadTestSuiteProperties; } public boolean isWritePropertiesToSahiConfig() { return writePropertiesToSahiConfig; } public void setWritePropertiesToSahiConfig(boolean writePropertiesToSahiConfig) { this.writePropertiesToSahiConfig = writePropertiesToSahiConfig; } }