CCM NG: Split class ConfigurationManager into smaller classes to reduce complexity.
git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@3825 8810af33-2d31-482b-a856-94f89814c4dfpull/2/head
parent
cc7889143c
commit
73eef4aeb0
|
|
@ -20,7 +20,6 @@ package org.libreccm.categorization;
|
|||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.message.FormattedMessage;
|
||||
import org.libreccm.core.AbstractEntityRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* Copyright (C) 2016 LibreCCM Foundation.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
package org.libreccm.configuration;
|
||||
|
||||
import static org.libreccm.configuration.ConfigurationConstants.*;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.libreccm.categorization.Category;
|
||||
import org.libreccm.categorization.CategoryManager;
|
||||
import org.libreccm.categorization.CategoryRepository;
|
||||
import org.libreccm.categorization.Domain;
|
||||
import org.libreccm.categorization.DomainRepository;
|
||||
import org.libreccm.web.CcmApplication;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
import javax.inject.Inject;
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
@RequestScoped
|
||||
public class ApplicationConfigurationManager {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(
|
||||
ApplicationConfigurationManager.class
|
||||
);
|
||||
|
||||
@Inject
|
||||
private ConfigurationManager confManager;
|
||||
|
||||
@Inject
|
||||
private SettingManager settingManager;
|
||||
|
||||
@Inject
|
||||
private SettingConverter settingConverter;
|
||||
|
||||
@Inject
|
||||
private DomainRepository domainRepo;
|
||||
|
||||
@Inject
|
||||
private CategoryRepository categoryRepo;
|
||||
|
||||
@Inject
|
||||
private CategoryManager categoryManager;
|
||||
|
||||
@Inject
|
||||
private EntityManager entityManager;
|
||||
|
||||
/**
|
||||
* Finds an application instance specific configuration and loads it values
|
||||
* from the registry.
|
||||
*
|
||||
* @param <T> The type of the configuration.
|
||||
* @param confClass The configuration class.
|
||||
* @param instance The application instance for which the settings are
|
||||
* loaded.
|
||||
*
|
||||
* @return The configuration for the provided application instance.
|
||||
*/
|
||||
public <T extends ApplicationConfiguration> T findConfiguration(
|
||||
final Class<T> confClass, final CcmApplication instance) {
|
||||
if (confClass == null) {
|
||||
throw new IllegalArgumentException("confClass can't be null");
|
||||
}
|
||||
|
||||
if (instance == null) {
|
||||
throw new IllegalArgumentException("instance can't be null");
|
||||
}
|
||||
|
||||
if (confClass.getAnnotation(Configuration.class) == null) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Provided class \"%s\" is not annotated with \"%s\".",
|
||||
confClass.getName(),
|
||||
Configuration.class.getName()));
|
||||
}
|
||||
|
||||
final String confName = String.format("%s.%s",
|
||||
confClass.getName(),
|
||||
instance.getPrimaryUrl());
|
||||
|
||||
return confManager.findConfiguration(confName, confClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a application instance configuration.
|
||||
*
|
||||
* @param configuration The configuration to save.
|
||||
* @param instance The application instance of which the configuration
|
||||
* stores the settings.
|
||||
*/
|
||||
public void saveConfiguration(final ApplicationConfiguration configuration,
|
||||
final CcmApplication instance) {
|
||||
if (configuration == null) {
|
||||
throw new IllegalArgumentException("Configuration can't be null");
|
||||
}
|
||||
|
||||
if (configuration.getClass().getAnnotation(Configuration.class) == null) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"The class \"%s\" of the provided object is not annotated "
|
||||
+ "with \"%s\".",
|
||||
configuration.getClass().getName(),
|
||||
Configuration.class.getName()));
|
||||
}
|
||||
|
||||
if (instance == null) {
|
||||
throw new IllegalArgumentException("Instance can't be null");
|
||||
}
|
||||
|
||||
final Field[] fields = configuration.getClass().getDeclaredFields();
|
||||
for (final Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
setSettingValue(configuration,
|
||||
instance,
|
||||
confManager.getSettingName(field),
|
||||
field.getType(),
|
||||
field.get(configuration));
|
||||
} catch (IllegalAccessException ex) {
|
||||
LOGGER.error(String.format(
|
||||
"Failed to write setting value for setting \"%s\" "
|
||||
+ "of configuration \"%s\"",
|
||||
confManager.getSettingName(field),
|
||||
configuration.getClass().getName()),
|
||||
ex);
|
||||
throw new IllegalStateException(String.format(
|
||||
"Failed to write setting value for setting \"%s\" "
|
||||
+ "of configuration \"%s\"",
|
||||
confManager.getSettingName(field),
|
||||
configuration.getClass().getName()),
|
||||
ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a setting of application instance configuration.
|
||||
*
|
||||
* @param <T> The value type of the setting.
|
||||
* @param configuration The configuration to which the settings belongs.
|
||||
* @param instance The application instance to which
|
||||
* @param settingName The name of the setting.
|
||||
* @param valueType The type of the value of the setting.
|
||||
* @param value The value to set.
|
||||
*/
|
||||
private <T> void setSettingValue(final Object configuration,
|
||||
final CcmApplication instance,
|
||||
final String settingName,
|
||||
final Class<T> valueType,
|
||||
final Object value) {
|
||||
final String settingPath = String.format(
|
||||
"%s.%s.%s",
|
||||
configuration.getClass().getName(),
|
||||
instance.getPrimaryUrl(),
|
||||
settingName);
|
||||
AbstractSetting<T> setting = settingManager.findSetting(settingPath, valueType);
|
||||
if (setting == null) {
|
||||
setting = settingConverter.createSettingForValueType(valueType);
|
||||
setting.setName(settingName);
|
||||
final Domain registry = domainRepo
|
||||
.findByDomainKey(REGISTRY_DOMAIN);
|
||||
final Category category = categoryRepo
|
||||
.findByPath(registry, configuration.getClass().getName());
|
||||
categoryManager.addObjectToCategory(setting, category);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final T settingValue = (T) value;
|
||||
setting.setValue(settingValue);
|
||||
|
||||
entityManager.merge(setting);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -23,22 +23,13 @@ import static org.libreccm.configuration.ConfigurationConstants.*;
|
|||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.message.FormattedMessage;
|
||||
import org.libreccm.categorization.Categorization;
|
||||
import org.libreccm.categorization.Category;
|
||||
import org.libreccm.categorization.CategoryManager;
|
||||
import org.libreccm.categorization.CategoryRepository;
|
||||
import org.libreccm.categorization.Domain;
|
||||
import org.libreccm.categorization.DomainRepository;
|
||||
import org.libreccm.core.CcmObject;
|
||||
import org.libreccm.l10n.LocalizedString;
|
||||
import org.libreccm.web.CcmApplication;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
|
|
@ -51,24 +42,25 @@ import javax.persistence.EntityManager;
|
|||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
@RequestScoped
|
||||
@SuppressWarnings({"PMD.GodClass",
|
||||
"PMD.TooManyMethods",
|
||||
"PMD.LongVariable",
|
||||
"PMD.ModifiedCyclomaticComplexity",
|
||||
"PMD.StandardCyclomaticComplexity",})
|
||||
public class ConfigurationManager {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(
|
||||
ConfigurationManager.class);
|
||||
|
||||
@Inject
|
||||
private SettingManager settingManager;
|
||||
|
||||
@Inject
|
||||
private SettingConverter settingConverter;
|
||||
|
||||
@Inject
|
||||
private CategoryManager categoryManager;
|
||||
|
||||
@Inject
|
||||
private CategoryRepository categoryRepository;
|
||||
private CategoryRepository categoryRepo;
|
||||
|
||||
@Inject
|
||||
private DomainRepository domainRepository;
|
||||
private DomainRepository domainRepo;
|
||||
|
||||
@Inject
|
||||
private EntityManager entityManager;
|
||||
|
|
@ -162,92 +154,6 @@ public class ConfigurationManager {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an application instance specific configuration and loads it values
|
||||
* from the registry.
|
||||
*
|
||||
* @param <T> The type of the configuration.
|
||||
* @param confClass The configuration class.
|
||||
* @param instance The application instance for which the settings are
|
||||
* loaded.
|
||||
*
|
||||
* @return The configuration for the provided application instance.
|
||||
*/
|
||||
public <T extends ApplicationConfiguration> T findConfiguration(
|
||||
final Class<T> confClass, final CcmApplication instance) {
|
||||
if (confClass == null) {
|
||||
throw new IllegalArgumentException("confClass can't be null");
|
||||
}
|
||||
|
||||
if (instance == null) {
|
||||
throw new IllegalArgumentException("instance can't be null");
|
||||
}
|
||||
|
||||
if (confClass.getAnnotation(Configuration.class) == null) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Provided class \"%s\" is not annotated with \"%s\".",
|
||||
confClass.getName(),
|
||||
Configuration.class.getName()));
|
||||
}
|
||||
|
||||
final String confName = String.format("%s.%s",
|
||||
confClass.getName(),
|
||||
instance.getPrimaryUrl());
|
||||
|
||||
return findConfiguration(confName, confClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a application instance configuration.
|
||||
*
|
||||
* @param configuration The configuration to save.
|
||||
* @param instance The application instance of which the configuration
|
||||
* stores the settings.
|
||||
*/
|
||||
public void saveConfiguration(final ApplicationConfiguration configuration,
|
||||
final CcmApplication instance) {
|
||||
if (configuration == null) {
|
||||
throw new IllegalArgumentException("Configuration can't be null");
|
||||
}
|
||||
|
||||
if (configuration.getClass().getAnnotation(Configuration.class) == null) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"The class \"%s\" of the provided object is not annotated "
|
||||
+ "with \"%s\".",
|
||||
configuration.getClass().getName(),
|
||||
Configuration.class.getName()));
|
||||
}
|
||||
|
||||
if (instance == null) {
|
||||
throw new IllegalArgumentException("Instance can't be null");
|
||||
}
|
||||
|
||||
final Field[] fields = configuration.getClass().getDeclaredFields();
|
||||
for (final Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
setSettingValue(configuration,
|
||||
instance,
|
||||
getSettingName(field),
|
||||
field.getType(),
|
||||
field.get(configuration));
|
||||
} catch (IllegalAccessException ex) {
|
||||
LOGGER.error(String.format(
|
||||
"Failed to write setting value for setting \"%s\" "
|
||||
+ "of configuration \"%s\"",
|
||||
getSettingName(field),
|
||||
configuration.getClass().getName()),
|
||||
ex);
|
||||
throw new IllegalStateException(String.format(
|
||||
"Failed to write setting value for setting \"%s\" "
|
||||
+ "of configuration \"%s\"",
|
||||
getSettingName(field),
|
||||
configuration.getClass().getName()),
|
||||
ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ConfigurationInfo} for a configuration.
|
||||
*
|
||||
|
|
@ -294,205 +200,14 @@ public class ConfigurationManager {
|
|||
for (final Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
if (field.getAnnotation(Setting.class) != null) {
|
||||
confInfo.addSetting(getSettingInfo(configuration,
|
||||
field.getName()));
|
||||
confInfo.addSetting(settingManager.getSettingInfo(
|
||||
configuration, field.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
return confInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link SettingInfo} instance for a setting.
|
||||
*
|
||||
* @param configuration The configuration class to which the settings
|
||||
* belongs.
|
||||
* @param name The name of the setting for which the
|
||||
* {@link SettingInfo} is generated.
|
||||
*
|
||||
* @return The {@link SettingInfo} for the provided configuration class.
|
||||
*/
|
||||
@SuppressWarnings({"PMD.NPathComplexity",
|
||||
"PMD.CyclomaticComplexity",
|
||||
"PMD.StandardCyclomaticComplexity"})
|
||||
public SettingInfo getSettingInfo(final Class<?> configuration,
|
||||
final String name) {
|
||||
if (configuration == null) {
|
||||
throw new IllegalArgumentException("Configuration can't be null");
|
||||
}
|
||||
|
||||
if (configuration.getAnnotation(Configuration.class) == null) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"The class \"%s\" of the provided object is not annotated "
|
||||
+ "with \"%s\".",
|
||||
configuration.getClass().getName(),
|
||||
Configuration.class.getName()));
|
||||
}
|
||||
|
||||
final Configuration confAnnotation = configuration.getAnnotation(
|
||||
Configuration.class);
|
||||
final String descBundle;
|
||||
if (confAnnotation.descBundle() == null
|
||||
|| confAnnotation.descBundle().isEmpty()) {
|
||||
descBundle = String.join("",
|
||||
configuration.getClass().getName(),
|
||||
"Description");
|
||||
} else {
|
||||
descBundle = confAnnotation.descBundle();
|
||||
}
|
||||
|
||||
final Field field;
|
||||
try {
|
||||
field = configuration.getDeclaredField(name);
|
||||
} catch (SecurityException | NoSuchFieldException ex) {
|
||||
LOGGER.warn(String.format(
|
||||
"Failed to generate SettingInfo for field \"%s\" of "
|
||||
+ "configuration \"%s\". Ignoring field.",
|
||||
configuration.getClass().getName(),
|
||||
name),
|
||||
ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (field.getAnnotation(Setting.class) == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Setting settingAnnotation = field.getAnnotation(Setting.class);
|
||||
final SettingInfo settingInfo = new SettingInfo();
|
||||
if (settingAnnotation.name() == null
|
||||
|| settingAnnotation.name().isEmpty()) {
|
||||
settingInfo.setName(field.getName());
|
||||
} else {
|
||||
settingInfo.setName(settingAnnotation.name());
|
||||
}
|
||||
|
||||
settingInfo.setValueType(field.getType().getName());
|
||||
|
||||
try {
|
||||
final Object conf = configuration.newInstance();
|
||||
settingInfo.setDefaultValue(field.get(conf).toString());
|
||||
} catch (InstantiationException | IllegalAccessException ex) {
|
||||
LOGGER.warn(String.format("Failed to create instance of \"%s\" to "
|
||||
+ "get default values.",
|
||||
configuration.getName()),
|
||||
ex);
|
||||
}
|
||||
|
||||
settingInfo.setConfClass(configuration.getName());
|
||||
|
||||
settingInfo.setDescBundle(descBundle);
|
||||
|
||||
if (settingAnnotation.labelKey() == null
|
||||
|| settingAnnotation.labelKey().isEmpty()) {
|
||||
settingInfo.setLabelKey(String.join(".", field.getName(),
|
||||
"label"));
|
||||
} else {
|
||||
settingInfo.setLabelKey(name);
|
||||
}
|
||||
|
||||
if (settingAnnotation.descKey() == null
|
||||
|| settingAnnotation.descKey().isEmpty()) {
|
||||
settingInfo.setDescKey(String.join(".",
|
||||
field.getName(),
|
||||
"descripotion"));
|
||||
} else {
|
||||
settingInfo.setDescKey(settingAnnotation.descKey());
|
||||
}
|
||||
|
||||
return settingInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* A low level method for finding a setting in the registry.
|
||||
*
|
||||
* @param <T> Type of the value of the setting
|
||||
* @param name The fully qualified name of the setting.
|
||||
* @param clazz The class of the setting.
|
||||
*
|
||||
* @return The requested setting if it exists in the registry, {@code null}
|
||||
* otherwise.
|
||||
*/
|
||||
public <T> AbstractSetting<T> findSetting(final String name,
|
||||
final Class<T> clazz) {
|
||||
LOGGER.debug(String.format(
|
||||
"Trying to find setting \"%s\" of type \"%s\"",
|
||||
name,
|
||||
clazz.getName()));
|
||||
final String[] tokens = name.split("\\.");
|
||||
LOGGER.debug(String.format("Setting name \"%s\" has %d tokens.",
|
||||
name,
|
||||
tokens.length));
|
||||
final String[] categoryTokens = Arrays.copyOfRange(tokens,
|
||||
0,
|
||||
tokens.length - 1);
|
||||
final String categoryPath = String.join(".", categoryTokens);
|
||||
LOGGER.debug(String.format("categoryPath for setting is \"%s\".",
|
||||
categoryPath));
|
||||
|
||||
final Domain registry = domainRepository
|
||||
.findByDomainKey(REGISTRY_DOMAIN);
|
||||
final Category category = categoryRepository.findByPath(registry,
|
||||
categoryPath);
|
||||
if (category == null) {
|
||||
LOGGER.warn(String.format(String.format(
|
||||
"Category \"%s\" for setting \"%s\" not found.",
|
||||
categoryPath,
|
||||
name)));
|
||||
return null;
|
||||
}
|
||||
|
||||
LOGGER.debug(String.format("Category has %d objects. Filtering.",
|
||||
category.getObjects().size()));
|
||||
final Optional<Categorization> result = category
|
||||
.getObjects()
|
||||
.stream()
|
||||
.filter((Categorization c)
|
||||
-> c.getCategorizedObject() instanceof AbstractSetting)
|
||||
.filter((Categorization c)
|
||||
-> ((AbstractSetting<?>) c.getCategorizedObject())
|
||||
.getName()
|
||||
.equals(tokens[tokens.length - 1]))
|
||||
.findFirst();
|
||||
|
||||
if (result.isPresent()) {
|
||||
final CcmObject object = result.get().getCategorizedObject();
|
||||
final AbstractSetting<?> entry = (AbstractSetting<?>) object;
|
||||
|
||||
if (clazz.isInstance(entry.getValue())) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final AbstractSetting<T> resultEntry
|
||||
= (AbstractSetting<T>) entry;
|
||||
return resultEntry;
|
||||
} else {
|
||||
LOGGER.warn(String.format("Setting \"%s\" found but is not of "
|
||||
+ "the requested type \"%s\".",
|
||||
name,
|
||||
clazz.getName()));
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
LOGGER.warn(String.format(
|
||||
"Setting \"%s\" was not found in category \"%s\".",
|
||||
name,
|
||||
categoryPath));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Low level method of saving a setting.
|
||||
*
|
||||
* @param setting The setting to save.
|
||||
*/
|
||||
public void saveSetting(final AbstractSetting<?> setting) {
|
||||
if (setting.getObjectId() == 0) {
|
||||
entityManager.persist(setting);
|
||||
} else {
|
||||
entityManager.merge(setting);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for generating the name of a setting. This method does not
|
||||
* check if the provided field is annotated with {@link Setting}. The caller
|
||||
|
|
@ -504,7 +219,7 @@ public class ConfigurationManager {
|
|||
* @return The name of the field or if the {@link Setting} annotation of the
|
||||
* field has a name value, the value of that field.
|
||||
*/
|
||||
private String getSettingName(final Field field) {
|
||||
String getSettingName(final Field field) {
|
||||
LOGGER.debug(String.format("Trying to get setting name from field: "
|
||||
+ "\"%s\"",
|
||||
field.getName()));
|
||||
|
|
@ -528,32 +243,32 @@ public class ConfigurationManager {
|
|||
* @throws IllegalArgumentException If there is not setting type for the
|
||||
* provided value type.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> AbstractSetting<T> createSettingForValueType(
|
||||
final Class<T> valueType) {
|
||||
|
||||
final String valueTypeName = valueType.getName();
|
||||
if (BigDecimal.class.getName().equals(valueTypeName)) {
|
||||
return (AbstractSetting<T>) new BigDecimalSetting();
|
||||
} else if (Boolean.class.getName().equals(valueTypeName)) {
|
||||
return (AbstractSetting<T>) new BooleanSetting();
|
||||
} else if (Double.class.getName().equals(valueTypeName)) {
|
||||
return (AbstractSetting<T>) new DoubleSetting();
|
||||
} else if (List.class.getName().equals(valueTypeName)) {
|
||||
return (AbstractSetting<T>) new StringListSetting();
|
||||
} else if (LocalizedString.class.getName().equals(valueTypeName)) {
|
||||
return (AbstractSetting<T>) new LocalizedStringSetting();
|
||||
} else if (Long.class.getName().equals(valueTypeName)) {
|
||||
return (AbstractSetting<T>) new LongSetting();
|
||||
} else if (Set.class.getName().equals(valueTypeName)) {
|
||||
return (AbstractSetting<T>) new EnumSetting();
|
||||
} else if (String.class.getName().equals(valueTypeName)) {
|
||||
return (AbstractSetting<T>) new StringSetting();
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"No setting type for value type \"%s\".", valueTypeName));
|
||||
}
|
||||
}
|
||||
// @SuppressWarnings("unchecked")
|
||||
// <T> AbstractSetting<T> createSettingForValueType(
|
||||
// final Class<T> valueType) {
|
||||
//
|
||||
// final String valueTypeName = valueType.getName();
|
||||
// if (BigDecimal.class.getName().equals(valueTypeName)) {
|
||||
// return (AbstractSetting<T>) new BigDecimalSetting();
|
||||
// } else if (Boolean.class.getName().equals(valueTypeName)) {
|
||||
// return (AbstractSetting<T>) new BooleanSetting();
|
||||
// } else if (Double.class.getName().equals(valueTypeName)) {
|
||||
// return (AbstractSetting<T>) new DoubleSetting();
|
||||
// } else if (List.class.getName().equals(valueTypeName)) {
|
||||
// return (AbstractSetting<T>) new StringListSetting();
|
||||
// } else if (LocalizedString.class.getName().equals(valueTypeName)) {
|
||||
// return (AbstractSetting<T>) new LocalizedStringSetting();
|
||||
// } else if (Long.class.getName().equals(valueTypeName)) {
|
||||
// return (AbstractSetting<T>) new LongSetting();
|
||||
// } else if (Set.class.getName().equals(valueTypeName)) {
|
||||
// return (AbstractSetting<T>) new EnumSetting();
|
||||
// } else if (String.class.getName().equals(valueTypeName)) {
|
||||
// return (AbstractSetting<T>) new StringSetting();
|
||||
// } else {
|
||||
// throw new IllegalArgumentException(String.format(
|
||||
// "No setting type for value type \"%s\".", valueTypeName));
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Sets a value on a setting in the registry.
|
||||
|
|
@ -576,12 +291,13 @@ public class ConfigurationManager {
|
|||
"Saving setting \"%s\" of type \"%s\"...",
|
||||
settingPath,
|
||||
valueType.getName()));
|
||||
AbstractSetting<T> setting = findSetting(settingPath, valueType);
|
||||
AbstractSetting<T> setting = settingManager.findSetting(settingPath,
|
||||
valueType);
|
||||
if (setting == null) {
|
||||
LOGGER.debug(String.format("Setting \"%s\" does not yet exist in "
|
||||
+ "database. Creating new setting.",
|
||||
settingPath));
|
||||
setting = createSettingForValueType(valueType);
|
||||
setting = settingConverter.createSettingForValueType(valueType);
|
||||
setting.setName(settingName);
|
||||
setting.setDisplayName(settingName);
|
||||
final Category category = findCategoryForNewSetting(configuration);
|
||||
|
|
@ -603,44 +319,6 @@ public class ConfigurationManager {
|
|||
entityManager.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a setting of application instance configuration.
|
||||
*
|
||||
* @param <T> The value type of the setting.
|
||||
* @param configuration The configuration to which the settings belongs.
|
||||
* @param instance The application instance to which
|
||||
* @param settingName The name of the setting.
|
||||
* @param valueType The type of the value of the setting.
|
||||
* @param value The value to set.
|
||||
*/
|
||||
private <T> void setSettingValue(final Object configuration,
|
||||
final CcmApplication instance,
|
||||
final String settingName,
|
||||
final Class<T> valueType,
|
||||
final Object value) {
|
||||
final String settingPath = String.format(
|
||||
"%s.%s.%s",
|
||||
configuration.getClass().getName(),
|
||||
instance.getPrimaryUrl(),
|
||||
settingName);
|
||||
AbstractSetting<T> setting = findSetting(settingPath, valueType);
|
||||
if (setting == null) {
|
||||
setting = createSettingForValueType(valueType);
|
||||
setting.setName(settingName);
|
||||
final Domain registry = domainRepository
|
||||
.findByDomainKey(REGISTRY_DOMAIN);
|
||||
final Category category = categoryRepository
|
||||
.findByPath(registry, configuration.getClass().getName());
|
||||
categoryManager.addObjectToCategory(setting, category);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final T settingValue = (T) value;
|
||||
setting.setValue(settingValue);
|
||||
|
||||
entityManager.merge(setting);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for loading a configuration from the registry.
|
||||
*
|
||||
|
|
@ -657,13 +335,8 @@ public class ConfigurationManager {
|
|||
* @return An instance of the configuration class with all setting fields
|
||||
* set to the values stored in the registry.
|
||||
*/
|
||||
private <T> T findConfiguration(final String confName,
|
||||
<T> T findConfiguration(final String confName,
|
||||
final Class<T> confClass) {
|
||||
final Domain registry = domainRepository
|
||||
.findByDomainKey(REGISTRY_DOMAIN);
|
||||
final Category category = categoryRepository.findByPath(registry,
|
||||
confName);
|
||||
|
||||
final T conf;
|
||||
try {
|
||||
conf = confClass.newInstance();
|
||||
|
|
@ -675,7 +348,9 @@ public class ConfigurationManager {
|
|||
return null;
|
||||
}
|
||||
|
||||
if (category == null) {
|
||||
final Domain registry = domainRepo
|
||||
.findByDomainKey(REGISTRY_DOMAIN);
|
||||
if (categoryRepo.findByPath(registry, confName) == null) {
|
||||
return conf;
|
||||
}
|
||||
|
||||
|
|
@ -690,8 +365,8 @@ public class ConfigurationManager {
|
|||
confClass.getName(),
|
||||
getSettingName(field));
|
||||
final Class<?> settingType = field.getType();
|
||||
final AbstractSetting<?> setting = findSetting(settingPath,
|
||||
settingType);
|
||||
final AbstractSetting<?> setting = settingManager.findSetting(
|
||||
settingPath, settingType);
|
||||
if (setting != null) {
|
||||
try {
|
||||
LOGGER.debug("Setting \"{}\" found. Value: %s",
|
||||
|
|
@ -717,7 +392,7 @@ public class ConfigurationManager {
|
|||
configuration.getClass().getName());
|
||||
final String categoryPath = configuration.getClass().getName();
|
||||
final String[] tokens = categoryPath.split("\\.");
|
||||
final Domain registry = domainRepository
|
||||
final Domain registry = domainRepo
|
||||
.findByDomainKey(REGISTRY_DOMAIN);
|
||||
|
||||
final Category[] categories = new Category[tokens.length];
|
||||
|
|
@ -729,7 +404,7 @@ public class ConfigurationManager {
|
|||
LOGGER.debug("#findCategoryForNewSetting: "
|
||||
+ "Checking if category \"{}\" exists.",
|
||||
path);
|
||||
final Category category = categoryRepository.findByPath(registry,
|
||||
final Category category = categoryRepo.findByPath(registry,
|
||||
path);
|
||||
if (category == null) {
|
||||
LOGGER.debug("#findCategoryForNewSetting: "
|
||||
|
|
@ -794,7 +469,7 @@ public class ConfigurationManager {
|
|||
final Category category = new Category();
|
||||
category.setName(name);
|
||||
category.setDisplayName(name);
|
||||
categoryRepository.save(category);
|
||||
categoryRepo.save(category);
|
||||
entityManager.flush();
|
||||
categoryManager.addSubCategoryToCategory(category, parent);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (C) 2016 LibreCCM Foundation.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
package org.libreccm.configuration;
|
||||
|
||||
import org.libreccm.l10n.LocalizedString;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
|
||||
/**
|
||||
* Helper class for converting values to settings.
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
@RequestScoped
|
||||
class SettingConverter {
|
||||
|
||||
private final Map<String, Class<? extends AbstractSetting<?>>> typeMap;
|
||||
|
||||
public SettingConverter() {
|
||||
typeMap = new HashMap<>();
|
||||
typeMap.put(BigDecimal.class.getName(), BigDecimalSetting.class);
|
||||
typeMap.put(Boolean.class.getName(), BooleanSetting.class);
|
||||
typeMap.put(Double.class.getName(), DoubleSetting.class);
|
||||
typeMap.put(List.class.getName(), StringListSetting.class);
|
||||
typeMap.put(LocalizedString.class.getName(),
|
||||
LocalizedStringSetting.class);
|
||||
typeMap.put(Long.class.getName(), LongSetting.class);
|
||||
typeMap.put(Set.class.getName(), EnumSetting.class);
|
||||
typeMap.put(String.class.getName(), StringSetting.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a setting instance of a specific value type.
|
||||
*
|
||||
* @param <T> Type variable.
|
||||
* @param valueType The type of the value of the setting to create.
|
||||
*
|
||||
* @return An setting instance of the provided value type.
|
||||
*
|
||||
* @throws IllegalArgumentException If there is not setting type for the
|
||||
* provided value type.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
<T> AbstractSetting<T> createSettingForValueType(final Class<T> valueType) {
|
||||
|
||||
final String valueTypeName = valueType.getName();
|
||||
final Class<? extends AbstractSetting<?>> clazz = typeMap.get(
|
||||
valueTypeName);
|
||||
|
||||
if (clazz == null) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"No setting type for value type \"%s\".", valueTypeName));
|
||||
} else {
|
||||
try {
|
||||
return (AbstractSetting<T>) clazz.newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException ex) {
|
||||
throw new IllegalStateException(
|
||||
"Failed to create setting instance.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
* Copyright (C) 2016 LibreCCM Foundation.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
package org.libreccm.configuration;
|
||||
|
||||
import static org.libreccm.configuration.ConfigurationConstants.*;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.libreccm.categorization.Categorization;
|
||||
import org.libreccm.categorization.Category;
|
||||
import org.libreccm.categorization.CategoryRepository;
|
||||
import org.libreccm.categorization.Domain;
|
||||
import org.libreccm.categorization.DomainRepository;
|
||||
import org.libreccm.core.CcmObject;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
import javax.inject.Inject;
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
/**
|
||||
* Manages settings in the registry. Normally there should be no need to use
|
||||
* this class directly because the {@link ConfigurationManager} provide the same
|
||||
* public methods for accessing settings than this class. The purpose of this
|
||||
* class is only to separate the logic for managing settings from the logic for
|
||||
* managing configuration classes and to reduce the complexity of the
|
||||
* {@link ConfigurationManager} class
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
@RequestScoped
|
||||
public class SettingManager {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(
|
||||
SettingManager.class);
|
||||
|
||||
@Inject
|
||||
private CategoryRepository categoryRepo;
|
||||
|
||||
@Inject
|
||||
private DomainRepository domainRepo;
|
||||
|
||||
@Inject
|
||||
private EntityManager entityManager;
|
||||
|
||||
/**
|
||||
* Create a {@link SettingInfo} instance for a setting.
|
||||
*
|
||||
* @param configuration The configuration class to which the settings
|
||||
* belongs.
|
||||
* @param name The name of the setting for which the
|
||||
* {@link SettingInfo} is generated.
|
||||
*
|
||||
* @return The {@link SettingInfo} for the provided configuration class.
|
||||
*/
|
||||
@SuppressWarnings({"PMD.NPathComplexity",
|
||||
"PMD.CyclomaticComplexity",
|
||||
"PMD.StandardCyclomaticComplexity"})
|
||||
public SettingInfo getSettingInfo(final Class<?> configuration,
|
||||
final String name) {
|
||||
if (configuration == null) {
|
||||
throw new IllegalArgumentException("Configuration can't be null");
|
||||
}
|
||||
|
||||
if (configuration.getAnnotation(Configuration.class) == null) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"The class \"%s\" of the provided object is not annotated "
|
||||
+ "with \"%s\".",
|
||||
configuration.getClass().getName(),
|
||||
Configuration.class.getName()));
|
||||
}
|
||||
|
||||
// final Configuration confAnnotation = configuration.getAnnotation(
|
||||
// Configuration.class);
|
||||
// final String descBundle;
|
||||
// if (confAnnotation.descBundle() == null
|
||||
// || confAnnotation.descBundle().isEmpty()) {
|
||||
// descBundle = String.join("",
|
||||
// configuration.getClass().getName(),
|
||||
// "Description");
|
||||
// } else {
|
||||
// descBundle = confAnnotation.descBundle();
|
||||
// }
|
||||
|
||||
|
||||
|
||||
final Field field;
|
||||
try {
|
||||
field = configuration.getDeclaredField(name);
|
||||
} catch (SecurityException | NoSuchFieldException ex) {
|
||||
LOGGER.warn(String.format(
|
||||
"Failed to generate SettingInfo for field \"%s\" of "
|
||||
+ "configuration \"%s\". Ignoring field.",
|
||||
configuration.getClass().getName(),
|
||||
name),
|
||||
ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (field.getAnnotation(Setting.class) == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Setting settingAnnotation = field.getAnnotation(Setting.class);
|
||||
final SettingInfo settingInfo = new SettingInfo();
|
||||
if (settingAnnotation.name() == null
|
||||
|| settingAnnotation.name().isEmpty()) {
|
||||
settingInfo.setName(field.getName());
|
||||
} else {
|
||||
settingInfo.setName(settingAnnotation.name());
|
||||
}
|
||||
|
||||
settingInfo.setValueType(field.getType().getName());
|
||||
|
||||
try {
|
||||
final Object conf = configuration.newInstance();
|
||||
settingInfo.setDefaultValue(field.get(conf).toString());
|
||||
} catch (InstantiationException | IllegalAccessException ex) {
|
||||
LOGGER.warn(String.format("Failed to create instance of \"%s\" to "
|
||||
+ "get default values.",
|
||||
configuration.getName()),
|
||||
ex);
|
||||
}
|
||||
|
||||
settingInfo.setConfClass(configuration.getName());
|
||||
settingInfo.setDescBundle(getDescBundle(configuration));
|
||||
|
||||
if (settingAnnotation.labelKey() == null
|
||||
|| settingAnnotation.labelKey().isEmpty()) {
|
||||
settingInfo.setLabelKey(String.join(".", field.getName(),
|
||||
"label"));
|
||||
} else {
|
||||
settingInfo.setLabelKey(name);
|
||||
}
|
||||
|
||||
if (settingAnnotation.descKey() == null
|
||||
|| settingAnnotation.descKey().isEmpty()) {
|
||||
settingInfo.setDescKey(String.join(".",
|
||||
field.getName(),
|
||||
"descripotion"));
|
||||
} else {
|
||||
settingInfo.setDescKey(settingAnnotation.descKey());
|
||||
}
|
||||
|
||||
return settingInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* A low level method for finding a setting in the registry.
|
||||
*
|
||||
* @param <T> Type of the value of the setting
|
||||
* @param name The fully qualified name of the setting.
|
||||
* @param clazz The class of the setting.
|
||||
*
|
||||
* @return The requested setting if it exists in the registry, {@code null}
|
||||
* otherwise.
|
||||
*/
|
||||
public <T> AbstractSetting<T> findSetting(final String name,
|
||||
final Class<T> clazz) {
|
||||
LOGGER.debug(String.format(
|
||||
"Trying to find setting \"%s\" of type \"%s\"",
|
||||
name,
|
||||
clazz.getName()));
|
||||
final String[] tokens = name.split("\\.");
|
||||
LOGGER.debug(String.format("Setting name \"%s\" has %d tokens.",
|
||||
name,
|
||||
tokens.length));
|
||||
final String[] categoryTokens = Arrays.copyOfRange(tokens,
|
||||
0,
|
||||
tokens.length - 1);
|
||||
final String categoryPath = String.join(".", categoryTokens);
|
||||
LOGGER.debug(String.format("categoryPath for setting is \"%s\".",
|
||||
categoryPath));
|
||||
|
||||
final Domain registry = domainRepo
|
||||
.findByDomainKey(REGISTRY_DOMAIN);
|
||||
final Category category = categoryRepo.findByPath(registry,
|
||||
categoryPath);
|
||||
if (category == null) {
|
||||
LOGGER.warn(String.format(String.format(
|
||||
"Category \"%s\" for setting \"%s\" not found.",
|
||||
categoryPath,
|
||||
name)));
|
||||
return null;
|
||||
}
|
||||
|
||||
LOGGER.debug(String.format("Category has %d objects. Filtering.",
|
||||
category.getObjects().size()));
|
||||
final Optional<Categorization> result = category
|
||||
.getObjects()
|
||||
.stream()
|
||||
.filter((Categorization c)
|
||||
-> c.getCategorizedObject() instanceof AbstractSetting)
|
||||
.filter((Categorization c)
|
||||
-> ((AbstractSetting<?>) c.getCategorizedObject())
|
||||
.getName()
|
||||
.equals(tokens[tokens.length - 1]))
|
||||
.findFirst();
|
||||
|
||||
if (result.isPresent()) {
|
||||
final CcmObject object = result.get().getCategorizedObject();
|
||||
final AbstractSetting<?> entry = (AbstractSetting<?>) object;
|
||||
|
||||
if (clazz.isInstance(entry.getValue())) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final AbstractSetting<T> resultEntry
|
||||
= (AbstractSetting<T>) entry;
|
||||
return resultEntry;
|
||||
} else {
|
||||
LOGGER.warn(String.format("Setting \"%s\" found but is not of "
|
||||
+ "the requested type \"%s\".",
|
||||
name,
|
||||
clazz.getName()));
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
LOGGER.warn(String.format(
|
||||
"Setting \"%s\" was not found in category \"%s\".",
|
||||
name,
|
||||
categoryPath));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Low level method of saving a setting.
|
||||
*
|
||||
* @param setting The setting to save.
|
||||
*/
|
||||
public void saveSetting(final AbstractSetting<?> setting) {
|
||||
if (setting.getObjectId() == 0) {
|
||||
entityManager.persist(setting);
|
||||
} else {
|
||||
entityManager.merge(setting);
|
||||
}
|
||||
}
|
||||
|
||||
private String getDescBundle(final Class<?> configuration) {
|
||||
final Configuration confAnnotation = configuration.getAnnotation(
|
||||
Configuration.class);
|
||||
if (confAnnotation.descBundle() == null
|
||||
|| confAnnotation.descBundle().isEmpty()) {
|
||||
return String.join("",
|
||||
configuration.getClass().getName(),
|
||||
"Description");
|
||||
} else {
|
||||
return confAnnotation.descBundle();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue