/**
* Copyright Plugtree LLC
*
* 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.plugtree.solrmeter.model;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Pattern;
import com.plugtree.solrmeter.runMode.SolrMeterRunModeHeadless;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Holds all the current configuration. The settings page will change the values of this configuration
* but the changes won't be persistent unless a exportConfiguration method is invoked.
* @author tflobbe
*
*/
public class SolrMeterConfiguration {
public static final String DOCUMENTS_ID = "solr.documentIdField";
public static final String FIELDS_FILE_PATH = "solr.documentFieldsFile";
public static final String QUERY_TYPE = "solr.search.queryType";
public static final String SOLR_ADD_URL = "solr.addUrl";
public static final String CONFIGURATION_FILE_PATH_PROPERTY = "solrmeter.configurationFile";
public static final String RUN_MODE_PROPERTY = "solrmeter.runMode";
public static String SOLR_SEARCH_URL = "solr.searchUrl";
public static String QUERIES_FILE_PATH = "solr.queriesFiles";
public static String UPDATES_FILE_PATH = "solr.updatesFiles";
public static String DELETES_FILE_PATH = "solr.deletesFiles";
public static String INSERTS_FILE_PATH = "solr.insertsFiles";
public static String QUERIES_PER_SECOND = "solr.load.queriespersecond";
public static String UPDATES_PER_SECOND = "solr.load.updatespersecond";
public static String DELETES_PER_SECOND = "solr.load.deletespersecond";
public static String INSERTS_PER_SECOND = "solr.load.deletespersecond";
public static String TEST_TIME = "solr.testTime";
public static String QUERY_METHOD = "solr.queryMethod";
private static Logger logger = LoggerFactory.getLogger(SolrMeterConfiguration.class);
private static String FILE_CONFIG_NAME = "solrmeter.properties";
private static Properties prop = new Properties();
private static Map<String, String> transientProperties = new HashMap<String, String>();
static {
loadConfiguration();
}
private SolrMeterConfiguration() {
}
/**
* Returns the value currently being used for the property with key = 'name'
* or null if the key is not found. If a systsme property exists with the same key
* it will be returned. Configuration specified as system property can be changed
* on runtime.
* @param name the key of the property
* @return the system property if there is one for the key 'name'
* the configuration property if there is one for the key 'name'
* null if there is no configuration for the key 'name'
*/
public static String getProperty(String name) {
return getProperty(name, null);
}
/**
* Returns the value currently being used for the property with key = 'name'
* or 'defaultValue' if the key is not found. If a systsme property exists with the same key
* it will be returned. Configuration specified as system property can be changed
* on runtime.
* @param name the key of the property
* @return the system property if there is one for the key 'name'
* the configuration property if there is one for the key 'name'
* 'defaultValue' if there is no configuration for the key 'name'
*/
public static String getProperty(String name, String defaultValue) {
String systemProp = System.getProperty(name);
if(systemProp != null) {
return systemProp;
}
return prop.getProperty(name, defaultValue);
}
/**
* Sets the current configuration property for the key 'propertyName' to
* the value 'value' if it exists, or create a new configuration property for the
* key 'propertyName'. System properties can't be changed on runtime.
* @param propertyName the key of the configuration property
* @param value the value of the configuration
* @return the previous value of the specified key in this property list, or null if it did not have one.
*/
public static String setProperty(String propertyName, String value) {
return (String) prop.setProperty(propertyName, value);
}
/**
* Removes the key (and its corresponding value) from the configuration. This method does nothing if the key is not in the configuration.
* @param propertyKey
*/
public static void removeProperty(String propertyKey) {
prop.remove(propertyKey);
}
/**
*
* @param pattern
* @return All the configuration properties that match the specified pattern. System properties
* are not included.
*/
public static List<String> getKeys(Pattern pattern) {
List<String> keys = new LinkedList<String>();
for(Object propertyKey:prop.keySet()) {
if(pattern.matcher((String)propertyKey).matches()) {
keys.add((String)propertyKey);
}
}
return keys;
}
public static String getTransientProperty(String propertyName) {
return transientProperties.get(propertyName);
}
public static void setTransientProperty(String propertyName, String propertyValue) {
transientProperties.put(propertyName, propertyValue);
}
/**
* imports an existing configuration file to this test
* @param configurationFile
* @throws IOException
*/
public static void importConfiguration(File configurationFile) throws IOException {
prop.clear();
FileInputStream inputStrean;
try {
inputStrean = new FileInputStream(configurationFile);
prop.loadFromXML(inputStrean);
} catch (IOException e) {
logger.error("Failed to Import Configuration", e);
throw e;
}
}
/**
* Creates a file with the current configuration so it can be loaded in further tests.
* @param file
* @throws IOException
*/
public static void exportConfiguration(File file) throws IOException {
if(file.exists()) {
file.delete();
}
try {
FileOutputStream fos = new FileOutputStream(file);
prop.storeToXML(fos, "Solr Meter Configuration File. Generated at " + SimpleDateFormat.getDateInstance().format(new Date()));
} catch (IOException e) {
logger.error("Failed to export configuration", e);
throw e;
}
}
/**
* Forces the loading of the default configuration. Used by tests.
*
*/
public static void loadDefaultConfiguration(){
loadConfiguration(FILE_CONFIG_NAME);
}
/**
* Loads the configuration from the available files. If a file name is specified as a VM parameter, that file will be used,
* otherwise, the default configuration file will be used.
* @see SolrMeterConfiguration.getDefaultFile()
*/
public static void loadConfiguration() {
String fileName = System.getProperty(CONFIGURATION_FILE_PATH_PROPERTY);
if(fileName == null) {
fileName = getDefaultFile();
LoggerFactory.getLogger("boot").info("Loading Default configuration");
}
if(isXML(fileName)) {
try {
importConfiguration(new File(FileUtils.findFileAsString(fileName)));
} catch (FileNotFoundException e) {
logger.error("File '" + fileName + "' was not found. Will load default configuration.", e);
loadConfiguration(getDefaultFile());
} catch (IOException e) {
logger.error("There was an error trying to load configuration from file '" + fileName + "', will use the default configuration.", e);
loadConfiguration(getDefaultFile());
}
} else {
loadConfiguration(fileName);
}
}
public static boolean isHeadless() {
return getProperty(RUN_MODE_PROPERTY, "").equals(SolrMeterRunModeHeadless.RUN_MODE_NAME);
}
/**
* The default file can be an external file located at the same directory as solrmeter with the name
* solrmeter.properties or solrmeter.smc.xml. If non of this exists, then the default configuration file
* will be the the file located inside the SolrMeter jar called "solrmeter.properties"
* @return
*/
private static String getDefaultFile() {
File file = new File("./" + FILE_CONFIG_NAME);
if(file.exists()) {
return "./" + FILE_CONFIG_NAME;
}
file = new File("./" + FILE_CONFIG_NAME.replace(".properties", ".smc.xml"));
if(file.exists()) {
return "./" + FILE_CONFIG_NAME.replace(".properties", ".smc.xml");
}
return FILE_CONFIG_NAME;
}
/**
* Loads the configuration for the configuration file named 'fileName'
* @param fileName The name of the configuration file
*/
private static void loadConfiguration(String fileName) {
LoggerFactory.getLogger("boot").info("Loading Configuration with file " + fileName);
InputStream inStream = null;
try {
inStream = FileUtils.findFileAsStream(fileName);
if(inStream == null) {
LoggerFactory.getLogger("boot").info("Configuration File " + fileName + " not found");
throw new FileNotFoundException("Configuration File " + fileName + " not found");
}
} catch (IOException e1) {
throw new RuntimeException(e1);
}
try {
prop.clear();
prop.load(inStream);
} catch (IOException e) {
LoggerFactory.getLogger("boot").error("Error", e);
}
}
/**
* Simple method that is used to determine wether to asume the file as an XML file (exported from SolrMeter)
* or not (otherwise it will be considered as a .properties file)
* @param fileName
* @return
*/
private static boolean isXML(String fileName) {
return fileName.endsWith(".smc.xml");
}
}