.getInternalName());
// verify each new setting and persist them to the database
// note that if a new setting is the same as the old one, we do nothing - leave the old entity as is
for (Map.Entry<SystemSetting, String> e : settings.entrySet()) {
SystemSetting prop = e.getKey();
String value = e.getValue();
if (!skipValidation) {
verifyNewSystemConfigurationProperty(prop, value, settings);
}
SystemConfiguration existingConfig = existingConfigMap.get(prop.getInternalName());
if (e.getKey() == SystemSetting.LAST_SYSTEM_CONFIG_UPDATE_TIME) {
//we don't let the user persist their own last system config update time
//in any manner
lastUpdateTime = existingConfig;
} else if (existingConfig == null) {
value = transformSystemConfigurationPropertyToDb(prop, value, null);
existingConfig = new SystemConfiguration(prop.getInternalName(), value);
entityManager.persist(existingConfig);
changed = true;
existingConfigMap.put(existingConfig.getPropertyKey(), existingConfig);
} else {
//make sure we compare the new value with a database-agnostic value
//it is important to compare in the database-agnostic format instead
//of database specific because the conversion isn't reflective.
//Some legacy code somewhere is (or just used to) store booleans as "0"s and "1"s
//even though they are stored as strings and thus don't suffer from Oracle's
//lack of support for boolean data type. If we encounter such values, we convert
//them to "false"/"true" and store that value to database. This is a one way operation
//and therefore we need to compare the database-agnostic (i.e. "true"/"false") and
//not database specific.
//
//More importantly though, we store the password fields obfuscated, so we need to compare apples with
//apples here.
String existingValue = transformSystemConfigurationPropertyFromDb(prop,
existingConfig.getPropertyValue(), true);
//we need to unmask the new value so that we can compare for changes. only after that can we transform
//it into the DB format.
value = unmask(prop, value, existingValue);
//also for oracle, treat null and empty string as the same.
if ((isEmpty(existingValue) && !isEmpty(value))
|| (null != existingValue && !existingValue.equals(value))) {
//SystemSetting#isReadOnly should be a superset of the "fReadOnly" field in the database
//but let's just be super paranoid here...
if ((prop.isReadOnly() || (existingConfig.getFreadOnly() != null && existingConfig.getFreadOnly()
.booleanValue())) && !(isStorageSetting(prop) || ignoreReadOnly)) {
throw new IllegalArgumentException("The setting [" + prop.getInternalName()
+ "] is read-only - you cannot change its current value! Current value is ["
+ existingConfig.getPropertyValue() + "] while the new value was [" + value + "].");
}
//transform to the database-specific format