package org.ovirt.engine.core.dal.dbbroker.generic;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.ovirt.engine.core.common.businessentities.VdcOption;
import org.ovirt.engine.core.common.config.Config;
import org.ovirt.engine.core.common.config.ConfigValues;
import org.ovirt.engine.core.common.config.DataType;
import org.ovirt.engine.core.common.config.OptionBehaviourAttribute;
import org.ovirt.engine.core.compat.LogCompat;
import org.ovirt.engine.core.compat.LogFactoryCompat;
import org.ovirt.engine.core.compat.RefObject;
import org.ovirt.engine.core.compat.Version;
import org.ovirt.engine.core.dal.dbbroker.DbFacade;
import org.ovirt.engine.core.engineencryptutils.EncryptionUtils;
import org.ovirt.engine.core.utils.ConfigUtilsBase;
import org.ovirt.engine.core.utils.serialization.json.JsonObjectDeserializer;
public class DBConfigUtils extends ConfigUtilsBase {
private static final Map<String, Map<String, Object>> _vdcOptionCache = new HashMap<String, Map<String, Object>>();
/**
* Refreshes the VDC option cache.
*/
private static void RefreshVdcOptionCache(DbFacade db) {
_vdcOptionCache.clear();
List<VdcOption> list = db.getVdcOptionDAO().getAll();
for (VdcOption option : list) {
Map<String, Object> values = null;
if ((values = _vdcOptionCache.get(option.getoption_name())) != null) {
values.put(option.getversion(), GetValue(option));
} else {
values = new HashMap<String, Object>();
values.put(option.getversion(), GetValue(option));
_vdcOptionCache.put(option.getoption_name(), values);
}
}
}
private static Object parseValue(String value, String name, java.lang.Class<?> fieldType) {
if (value == null) {
return null;
}
try {
if (fieldType == Integer.class) {
return Integer.parseInt(value);
} else if (fieldType == Boolean.class) {
return Boolean.parseBoolean(value);
} else if (fieldType == Version.class) {
return new Version(value);
} else if (fieldType == java.util.Date.class) {
return new SimpleDateFormat("k:m:s").parse(value);
} else if (fieldType == Double.class) {
return Double.parseDouble(value);
} else if (Map.class.isAssignableFrom(fieldType)) {
/* This if statement is to make a difference between the old and the json-style
* map support:
* - if it is enclosed between brackets, then it is handled as json object and a map is returned
* - otherwise it is handled as a string, the client code handles parsing it
*/
if(StringUtils.startsWith(value, "{") && StringUtils.endsWith(value, "}")) {
return new JsonObjectDeserializer().deserialize(value, HashMap.class);
} else {
return value;
}
} else {
return value;
}
} catch (java.lang.Exception e2) {
log.errorFormat("Could not parse option {0} value.", name);
return null;
}
}
/**
* Returns the typed value of the given option. returns default value if option.option_value is null
*
* @param option
* @return
*/
private static Object GetValue(VdcOption option) {
Object result = option.getoption_value();
@SuppressWarnings("rawtypes")
java.lang.Class fieldType = null;
String defaultValue = null;
OptionBehaviourAttribute optionBehaviour = null;
@SuppressWarnings("rawtypes")
RefObject<java.lang.Class> tempRefObject = new RefObject<java.lang.Class>(fieldType);
RefObject<String> tempRefObject2 = new RefObject<String>(defaultValue);
RefObject<OptionBehaviourAttribute> tempRefObject3 = new RefObject<OptionBehaviourAttribute>(optionBehaviour);
boolean tempVar = ParseEnumValue(option.getoption_name(), tempRefObject, tempRefObject2, tempRefObject3);
fieldType = tempRefObject.argvalue;
defaultValue = tempRefObject2.argvalue;
optionBehaviour = tempRefObject3.argvalue;
if (tempVar) {
result = parseValue(option.getoption_value(), option.getoption_name(), fieldType);
// if null use default from @DefaultValueAttribute
if (result == null) {
result = parseValue(defaultValue, option.getoption_name(), fieldType);
}
if (optionBehaviour != null) {
Map<String, Object> values = null;
switch (optionBehaviour.behaviour()) {
// split string by comma for List<string> constructor
case CommaSeparatedStringArray:
result = Arrays.asList(((String) result).split("[,]", -1));
break;
case Password:
try {
String keyFile = getValueFromDBDefault(ConfigValues.keystoreUrl);
String passwd = getValueFromDBDefault(ConfigValues.keystorePass);
String alias = getValueFromDBDefault(ConfigValues.CertAlias);
result = EncryptionUtils.decrypt((String) result, keyFile, passwd, alias);
} catch (Exception e) {
log.errorFormat("Failed to decrypt value for property {0} will be used encrypted value",
option.getoption_name(), e.getMessage());
}
break;
case DomainsPasswordMap:
String keyFile = getValueFromDBDefault(ConfigValues.keystoreUrl);
String passwd = getValueFromDBDefault(ConfigValues.keystorePass);
String alias = getValueFromDBDefault(ConfigValues.CertAlias);
result = new DomainsPasswordMap((String) result, keyFile, passwd, alias);
break;
case ValueDependent:
// get the config that this value depends on
if ((values = _vdcOptionCache.get(optionBehaviour.dependentOn().toString())) != null) {
// its value is this value's prefix
String prefix = (String) values.get(Config.DefaultConfigurationVersion);
// combine the prefix with the 'real value'
if ((values = _vdcOptionCache
.get(String.format("%1$s%2$s", prefix, optionBehaviour.realValue()))) != null) {
// get value of the wanted config - assuming
// default!!
result = values.get(Config.DefaultConfigurationVersion);
}
}
break;
case CommaSeparatedVersionArray:
java.util.HashSet<Version> versions = new java.util.HashSet<Version>();
for (String ver : result.toString().split("[,]", -1)) {
try {
versions.add(new Version(ver));
} catch (java.lang.Exception e) {
log.errorFormat("Could not parse version {0} for config value {1}", ver,
option.getoption_name());
}
}
result = versions;
break;
}
}
}
return result;
}
/**
* Initializes a new instance of the <see cref="DBConfigUtils"/> class.
*/
public DBConfigUtils() {
this(true);
}
private DbFacade dbfacade = null;
/**
* Constructs a DBConfigUtils instance which does not use DbFacade. Used by the unit test.
*
* @param initDB
* Whether to use DbFacade
*/
public DBConfigUtils(boolean initDB) {
if (initDB) {
dbfacade = DbFacade.getInstance();
RefreshVdcOptionCache(dbfacade);
}
}
/**
* Sets a vdcoption value.
*
* @param name
* The name.
* @param value
* The value.
*/
@Override
protected void SetValue(String name, String value, String version) {
VdcOption vdcOption = dbfacade.getVdcOptionDAO().getByNameAndVersion(name, version);
vdcOption.setoption_value(value);
dbfacade.getVdcOptionDAO().update(vdcOption);
try {
// refresh the cache entry after update
_vdcOptionCache.get(vdcOption.getoption_name()).put(version, GetValue(vdcOption));
} catch (java.lang.Exception e) {
log.errorFormat("Could not update option {0} in cache.", name);
}
}
private static String getValueFromDBDefault(ConfigValues name) {
String returnValue = null;
Map<String, Object> values = null;
if ((values = _vdcOptionCache.get(name.toString())) != null
&& values.containsKey(Config.DefaultConfigurationVersion)) {
returnValue = (String) values.get(Config.DefaultConfigurationVersion);
} else {
VdcOption option = DbFacade.getInstance().getVdcOptionDAO().getByNameAndVersion(name.name(),
Config.DefaultConfigurationVersion);
if (option != null) {
returnValue = option.getoption_value();
}
}
return returnValue;
}
@Override
protected Object GetValue(DataType type, String name, String defaultValue) {
log.warnFormat("Using old GetValue for {0}.", name);
ConfigValues value = ConfigValues.valueOf(name);
switch (type) {
case Bool:
return this.<Boolean> GetValue(value, Config.DefaultConfigurationVersion);
case DateTime:
return this.<java.util.Date> GetValue(value, Config.DefaultConfigurationVersion);
case Int:
return this.<Integer> GetValue(value, Config.DefaultConfigurationVersion);
case Version:
return this.<Version> GetValue(value, Config.DefaultConfigurationVersion);
case Map:
return this.<Map<?, ?>> GetValue(value, Config.DefaultConfigurationVersion);
default:
return this.<String> GetValue(value, Config.DefaultConfigurationVersion);
}
}
@SuppressWarnings("unchecked")
@Override
public <T> T GetValue(ConfigValues name, String version) {
T returnValue;
Map<String, Object> values = null;
if ((values = _vdcOptionCache.get(name.toString())) != null && values.containsKey(version)) {
returnValue = (T) values.get(version);
} else {
VdcOption option = new VdcOption();
option.setoption_name(name.toString());
option.setoption_value(null);
// returns default value - version independent
returnValue = (T) GetValue(option);
// If just requested version is missing, add the default value with the requested version.
if (values != null) {
values.put(version, returnValue);
} else {
// Couldn't find this value at all, adding to cache.
Map<String, Object> defaultValues = new HashMap<String, Object>();
defaultValues.put(version, returnValue);
_vdcOptionCache.put(option.getoption_name(), defaultValues);
log.warn("Adding new value to configuration cache.");
}
log.warnFormat("Didn't find the value of {0} in DB for version {1} - using default: {2}",
name, version, returnValue);
}
return returnValue;
}
private static LogCompat log = LogFactoryCompat.getLog(DBConfigUtils.class);
}