CCM NG: More test cases for the new database driven category system

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@3775 8810af33-2d31-482b-a856-94f89814c4df
pull/2/head
jensp 2015-12-17 14:07:40 +00:00
parent 06e342af0c
commit 4b5a227772
10 changed files with 696 additions and 177 deletions

View File

@ -6,9 +6,13 @@
</Console> </Console>
</Appenders> </Appenders>
<Loggers> <Loggers>
<Root level="error"> <Root level="info">
<AppenderRef ref="Console"/> <AppenderRef ref="Console"/>
</Root> </Root>
<Logger name="com.arsdigita.packaging.Config"
level="debug">
<AppenderRef ref="Console"/>
</Logger>
<Logger name="com.arsdigita.web.CCMDispatcherServlet" <Logger name="com.arsdigita.web.CCMDispatcherServlet"
level="debug"> level="debug">
<AppenderRef ref="Console"/> <AppenderRef ref="Console"/>

View File

@ -27,6 +27,8 @@ import javax.enterprise.context.RequestScoped;
import javax.inject.Inject; import javax.inject.Inject;
import javax.persistence.NoResultException; import javax.persistence.NoResultException;
import javax.persistence.TypedQuery; import javax.persistence.TypedQuery;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/** /**
* *
@ -35,6 +37,9 @@ import javax.persistence.TypedQuery;
@RequestScoped @RequestScoped
public class CategoryRepository extends AbstractEntityRepository<Long, Category> { public class CategoryRepository extends AbstractEntityRepository<Long, Category> {
private static final Logger LOGGER = LogManager.getLogger(
CategoryRepository.class);
@Inject @Inject
private DomainRepository domainRepo; private DomainRepository domainRepo;
@ -56,7 +61,7 @@ public class CategoryRepository extends AbstractEntityRepository<Long, Category>
*/ */
public List<Category> getTopLevelCategories() { public List<Category> getTopLevelCategories() {
final TypedQuery<Category> query = getEntityManager().createNamedQuery( final TypedQuery<Category> query = getEntityManager().createNamedQuery(
"Category.topLevelCategories", Category.class); "Category.topLevelCategories", Category.class);
return query.getResultList(); return query.getResultList();
} }
@ -69,14 +74,14 @@ public class CategoryRepository extends AbstractEntityRepository<Long, Category>
final String[] tokens = path.split(":"); final String[] tokens = path.split(":");
if (tokens.length > 2) { if (tokens.length > 2) {
throw new InvalidCategoryPathException( throw new InvalidCategoryPathException(
"The provided path is invalid: More than one colon found. " "The provided path is invalid: More than one colon found. "
+ "Valid path format: domainKey:path"); + "Valid path format: domainKey:path");
} }
if (tokens.length < 2) { if (tokens.length < 2) {
throw new InvalidCategoryPathException( throw new InvalidCategoryPathException(
"The provided path is invalid: No domain found in path. " "The provided path is invalid: No domain found in path. "
+ "Valid path format: domainKey:path"); + "Valid path format: domainKey:path");
} }
final Domain domain; final Domain domain;
@ -84,8 +89,8 @@ public class CategoryRepository extends AbstractEntityRepository<Long, Category>
domain = domainRepo.findByDomainKey(tokens[0]); domain = domainRepo.findByDomainKey(tokens[0]);
} catch (NoResultException ex) { } catch (NoResultException ex) {
throw new InvalidCategoryPathException(String.format( throw new InvalidCategoryPathException(String.format(
"No domain identified by the key '%s' found.", "No domain identified by the key '%s' found.",
tokens[0]), tokens[0]),
ex); ex);
} }
@ -111,15 +116,20 @@ public class CategoryRepository extends AbstractEntityRepository<Long, Category>
normalizedPath.length()); normalizedPath.length());
} }
LOGGER.debug(String.format(
"Trying to find category with path \"%s\" in "
+ "domain \"%s\".",
normalizedPath,
domain.getDomainKey()));
final String[] tokens = normalizedPath.split("/"); final String[] tokens = normalizedPath.split("/");
Category current = domain.getRoot(); Category current = domain.getRoot();
for (String token : tokens) { for (String token : tokens) {
final Optional<Category> result = current.getSubCategories() final Optional<Category> result = current.getSubCategories()
.stream() .stream()
.filter((c) -> { .filter((c) -> {
return c.getName().equals(token); return c.getName().equals(token);
}) })
.findFirst(); .findFirst();
if (result.isPresent()) { if (result.isPresent()) {
current = result.get(); current = result.get();
} else { } else {
@ -135,7 +145,7 @@ public class CategoryRepository extends AbstractEntityRepository<Long, Category>
* subcategory or the an {@link Domain} as root category. * subcategory or the an {@link Domain} as root category.
* *
* @return A list of all orphaned categories. Normally this list should be * @return A list of all orphaned categories. Normally this list should be
* empty. * empty.
*/ */
public List<Category> getOrphanedCategories() { public List<Category> getOrphanedCategories() {
// TODO implement method // TODO implement method

View File

@ -42,6 +42,8 @@ import java.math.BigDecimal;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID;
import org.apache.logging.log4j.message.FormattedMessage;
/** /**
* Maps between configuration classes and the values stored in the registry. * Maps between configuration classes and the values stored in the registry.
@ -52,7 +54,7 @@ import java.util.Optional;
public class ConfigurationManager { public class ConfigurationManager {
private static final Logger LOGGER = LogManager.getLogger( private static final Logger LOGGER = LogManager.getLogger(
ConfigurationManager.class); ConfigurationManager.class);
@Inject @Inject
private CategoryManager categoryManager; private CategoryManager categoryManager;
@ -69,11 +71,11 @@ public class ConfigurationManager {
/** /**
* Load all settings of the provided configuration class. * Load all settings of the provided configuration class.
* *
* @param <T> Type of the configuration class. * @param <T> Type of the configuration class.
* @param confClass The configuration class. * @param confClass The configuration class.
* *
* @return An instance of the configuration class with all settings set to * @return An instance of the configuration class with all settings set to
* the values stored in the registry. * the values stored in the registry.
*/ */
public <T> T findConfiguration(final Class<T> confClass) { public <T> T findConfiguration(final Class<T> confClass) {
if (confClass == null) { if (confClass == null) {
@ -82,9 +84,9 @@ public class ConfigurationManager {
if (confClass.getAnnotation(Configuration.class) == null) { if (confClass.getAnnotation(Configuration.class) == null) {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"Provided class \"%s\" is not annotated with \"%s\".", "Provided class \"%s\" is not annotated with \"%s\".",
confClass.getName(), confClass.getName(),
Configuration.class.getName())); Configuration.class.getName()));
} }
final String confName = confClass.getName(); final String confName = confClass.getName();
@ -97,13 +99,11 @@ public class ConfigurationManager {
* registry. * registry.
* *
* @param configuration The configuration to save. The class of the provided * @param configuration The configuration to save. The class of the provided
* object must be annotation with * object must be annotation with {@link Configuration}.
* {@link Configuration}.
* *
* @throws IllegalArgumentException If the {@code configuration} parameter * @throws IllegalArgumentException If the {@code configuration} parameter
* is {@code null} or if the class of the * is {@code null} or if the class of the provided object is not annotation
* provided object is not annotation with * with {@link Configuration}.
* {@link Configuration}.
*/ */
public void saveConfiguration(final Object configuration) { public void saveConfiguration(final Object configuration) {
if (configuration == null) { if (configuration == null) {
@ -112,15 +112,27 @@ public class ConfigurationManager {
if (configuration.getClass().getAnnotation(Configuration.class) == null) { if (configuration.getClass().getAnnotation(Configuration.class) == null) {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"The class \"%s\" of the provided object is not annotated " "The class \"%s\" of the provided object is not annotated "
+ "with \"%s\".", + "with \"%s\".",
configuration.getClass().getName(), configuration.getClass().getName(),
Configuration.class.getName())); Configuration.class.getName()));
} }
LOGGER.debug(String.format("Saving configuration \"%s\"...",
configuration.getClass().getName()));
final Field[] fields = configuration.getClass().getDeclaredFields(); final Field[] fields = configuration.getClass().getDeclaredFields();
for (final Field field : fields) { for (final Field field : fields) {
field.setAccessible(true); field.setAccessible(true);
if (field.getAnnotation(Setting.class) == null) {
LOGGER.debug(String.format(
"Field \"%s\" of class \"%s\" is not "
+ "a setting. Ignoring it.",
configuration.getClass().getName(),
field.getName()));
continue;
}
try { try {
setSettingValue(configuration, setSettingValue(configuration,
getSettingName(field), getSettingName(field),
@ -128,16 +140,16 @@ public class ConfigurationManager {
field.get(configuration)); field.get(configuration));
} catch (IllegalAccessException ex) { } catch (IllegalAccessException ex) {
LOGGER.error(String.format( LOGGER.error(String.format(
"Failed to write setting value for setting \"%s\" " "Failed to write setting value for setting \"%s\" "
+ "of configuration \"%s\"", + "of configuration \"%s\"",
getSettingName(field), getSettingName(field),
configuration.getClass().getName()), configuration.getClass().getName()),
ex); ex);
throw new IllegalStateException(String.format( throw new IllegalStateException(String.format(
"Failed to write setting value for setting \"%s\" " "Failed to write setting value for setting \"%s\" "
+ "of configuration \"%s\"", + "of configuration \"%s\"",
getSettingName(field), getSettingName(field),
configuration.getClass().getName()), configuration.getClass().getName()),
ex); ex);
} }
} }
@ -147,15 +159,15 @@ public class ConfigurationManager {
* Finds an application instance specific configuration and loads it values * Finds an application instance specific configuration and loads it values
* from the registry. * from the registry.
* *
* @param <T> The type of the configuration. * @param <T> The type of the configuration.
* @param confClass The configuration class. * @param confClass The configuration class.
* @param instance The application instance for which the settings are * @param instance The application instance for which the settings are
* loaded. * loaded.
* *
* @return The configuration for the provided application instance. * @return The configuration for the provided application instance.
*/ */
public <T extends ApplicationConfiguration> T findConfiguration( public <T extends ApplicationConfiguration> T findConfiguration(
final Class<T> confClass, final CcmApplication instance) { final Class<T> confClass, final CcmApplication instance) {
if (confClass == null) { if (confClass == null) {
throw new IllegalArgumentException("confClass can't be null"); throw new IllegalArgumentException("confClass can't be null");
} }
@ -166,9 +178,9 @@ public class ConfigurationManager {
if (confClass.getAnnotation(Configuration.class) == null) { if (confClass.getAnnotation(Configuration.class) == null) {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"Provided class \"%s\" is not annotated with \"%s\".", "Provided class \"%s\" is not annotated with \"%s\".",
confClass.getName(), confClass.getName(),
Configuration.class.getName())); Configuration.class.getName()));
} }
final String confName = String.format("%s.%s", final String confName = String.format("%s.%s",
@ -182,8 +194,8 @@ public class ConfigurationManager {
* Saves a application instance configuration. * Saves a application instance configuration.
* *
* @param configuration The configuration to save. * @param configuration The configuration to save.
* @param instance The application instance of which the configuration * @param instance The application instance of which the configuration
* stores the settings. * stores the settings.
*/ */
public void saveConfiguration(final ApplicationConfiguration configuration, public void saveConfiguration(final ApplicationConfiguration configuration,
final CcmApplication instance) { final CcmApplication instance) {
@ -193,10 +205,10 @@ public class ConfigurationManager {
if (configuration.getClass().getAnnotation(Configuration.class) == null) { if (configuration.getClass().getAnnotation(Configuration.class) == null) {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"The class \"%s\" of the provided object is not annotated " "The class \"%s\" of the provided object is not annotated "
+ "with \"%s\".", + "with \"%s\".",
configuration.getClass().getName(), configuration.getClass().getName(),
Configuration.class.getName())); Configuration.class.getName()));
} }
if (instance == null) { if (instance == null) {
@ -214,16 +226,16 @@ public class ConfigurationManager {
field.get(configuration)); field.get(configuration));
} catch (IllegalAccessException ex) { } catch (IllegalAccessException ex) {
LOGGER.error(String.format( LOGGER.error(String.format(
"Failed to write setting value for setting \"%s\" " "Failed to write setting value for setting \"%s\" "
+ "of configuration \"%s\"", + "of configuration \"%s\"",
getSettingName(field), getSettingName(field),
configuration.getClass().getName()), configuration.getClass().getName()),
ex); ex);
throw new IllegalStateException(String.format( throw new IllegalStateException(String.format(
"Failed to write setting value for setting \"%s\" " "Failed to write setting value for setting \"%s\" "
+ "of configuration \"%s\"", + "of configuration \"%s\"",
getSettingName(field), getSettingName(field),
configuration.getClass().getName()), configuration.getClass().getName()),
ex); ex);
} }
} }
@ -235,7 +247,7 @@ public class ConfigurationManager {
* @param configuration The configuration for which the info is generated. * @param configuration The configuration for which the info is generated.
* *
* @return a {@link ConfigurationInfo} instance describing the provided * @return a {@link ConfigurationInfo} instance describing the provided
* configuration. * configuration.
*/ */
public ConfigurationInfo getConfigurationInfo(final Class<?> configuration) { public ConfigurationInfo getConfigurationInfo(final Class<?> configuration) {
if (configuration == null) { if (configuration == null) {
@ -244,14 +256,14 @@ public class ConfigurationManager {
if (configuration.getAnnotation(Configuration.class) == null) { if (configuration.getAnnotation(Configuration.class) == null) {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"The class \"%s\" of the provided object is not annotated " "The class \"%s\" of the provided object is not annotated "
+ "with \"%s\".", + "with \"%s\".",
configuration.getClass().getName(), configuration.getClass().getName(),
Configuration.class.getName())); Configuration.class.getName()));
} }
final Configuration annotation = configuration.getAnnotation( final Configuration annotation = configuration.getAnnotation(
Configuration.class); Configuration.class);
final ConfigurationInfo confInfo = new ConfigurationInfo(); final ConfigurationInfo confInfo = new ConfigurationInfo();
confInfo.setName(configuration.getClass().getName()); confInfo.setName(configuration.getClass().getName());
@ -274,9 +286,9 @@ public class ConfigurationManager {
* Create a {@link SettingInfo} instance for a setting. * Create a {@link SettingInfo} instance for a setting.
* *
* @param configuration The configuration class to which the settings * @param configuration The configuration class to which the settings
* belongs. * belongs.
* @param name The name of the setting for which the * @param name The name of the setting for which the {@link SettingInfo} is
* {@link SettingInfo} is generated. * generated.
* *
* @return The {@link SettingInfo} for the provided configuration class. * @return The {@link SettingInfo} for the provided configuration class.
*/ */
@ -288,14 +300,14 @@ public class ConfigurationManager {
if (configuration.getAnnotation(Configuration.class) == null) { if (configuration.getAnnotation(Configuration.class) == null) {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"The class \"%s\" of the provided object is not annotated " "The class \"%s\" of the provided object is not annotated "
+ "with \"%s\".", + "with \"%s\".",
configuration.getClass().getName(), configuration.getClass().getName(),
Configuration.class.getName())); Configuration.class.getName()));
} }
final Configuration confAnnotation = configuration.getAnnotation( final Configuration confAnnotation = configuration.getAnnotation(
Configuration.class); Configuration.class);
final String descBundle = confAnnotation.descBundle(); final String descBundle = confAnnotation.descBundle();
final Field field; final Field field;
@ -303,10 +315,10 @@ public class ConfigurationManager {
field = configuration.getDeclaredField(name); field = configuration.getDeclaredField(name);
} catch (SecurityException | NoSuchFieldException ex) { } catch (SecurityException | NoSuchFieldException ex) {
LOGGER.warn(String.format( LOGGER.warn(String.format(
"Failed to generate SettingInfo for field \"%s\" of " "Failed to generate SettingInfo for field \"%s\" of "
+ "configuration \"%s\". Ignoring field.", + "configuration \"%s\". Ignoring field.",
configuration.getClass().getName(), configuration.getClass().getName(),
name), name),
ex); ex);
return null; return null;
} }
@ -318,7 +330,7 @@ public class ConfigurationManager {
final Setting settingAnnotation = field.getAnnotation(Setting.class); final Setting settingAnnotation = field.getAnnotation(Setting.class);
final SettingInfo settingInfo = new SettingInfo(); final SettingInfo settingInfo = new SettingInfo();
if (settingAnnotation.name() == null if (settingAnnotation.name() == null
|| settingAnnotation.name().isEmpty()) { || settingAnnotation.name().isEmpty()) {
settingInfo.setName(field.getName()); settingInfo.setName(field.getName());
} else { } else {
settingInfo.setName(settingAnnotation.name()); settingInfo.setName(settingAnnotation.name());
@ -331,7 +343,7 @@ public class ConfigurationManager {
settingInfo.setDefaultValue(field.get(conf).toString()); settingInfo.setDefaultValue(field.get(conf).toString());
} catch (InstantiationException | IllegalAccessException ex) { } catch (InstantiationException | IllegalAccessException ex) {
LOGGER.warn(String.format("Failed to create instance of \"%s\" to " LOGGER.warn(String.format("Failed to create instance of \"%s\" to "
+ "get default values.", + "get default values.",
configuration.getName()), configuration.getName()),
ex); ex);
} }
@ -347,19 +359,19 @@ public class ConfigurationManager {
/** /**
* A low level method for finding a setting in the registry. * A low level method for finding a setting in the registry.
* *
* @param <T> Type of the value of the setting * @param <T> Type of the value of the setting
* @param name The fully qualified name of the setting. * @param name The fully qualified name of the setting.
* @param clazz The class of the setting. * @param clazz The class of the setting.
* *
* @return The requested setting if it exists in the registry, {@code null} * @return The requested setting if it exists in the registry, {@code null}
* otherwise. * otherwise.
*/ */
public <T> AbstractSetting<T> findSetting(final String name, public <T> AbstractSetting<T> findSetting(final String name,
final Class<T> clazz) { final Class<T> clazz) {
LOGGER.debug(String.format( LOGGER.debug(String.format(
"Trying to find setting \"%s\" of type \"%s\"", "Trying to find setting \"%s\" of type \"%s\"",
name, name,
clazz.getName())); clazz.getName()));
final String[] tokens = name.split("\\."); final String[] tokens = name.split("\\.");
LOGGER.debug(String.format("Setting name \"%s\" has %d tokens.", LOGGER.debug(String.format("Setting name \"%s\" has %d tokens.",
name, name,
@ -372,29 +384,29 @@ public class ConfigurationManager {
categoryPath)); categoryPath));
final Domain registry = domainRepository final Domain registry = domainRepository
.findByDomainKey(REGISTRY_DOMAIN); .findByDomainKey(REGISTRY_DOMAIN);
final Category category = categoryRepository.findByPath(registry, final Category category = categoryRepository.findByPath(registry,
categoryPath); categoryPath);
if (category == null) { if (category == null) {
LOGGER.warn(String.format(String.format( LOGGER.warn(String.format(String.format(
"Category \"%s\" for setting \"%s\" not found.", "Category \"%s\" for setting \"%s\" not found.",
categoryPath, categoryPath,
name))); name)));
return null; return null;
} }
LOGGER.debug(String.format("Category has %d objects. Filtering.", LOGGER.debug(String.format("Category has %d objects. Filtering.",
category.getObjects().size())); category.getObjects().size()));
final Optional<Categorization> result = category final Optional<Categorization> result = category
.getObjects() .getObjects()
.stream() .stream()
.filter((Categorization c) .filter((Categorization c)
-> c.getCategorizedObject() instanceof AbstractSetting) -> c.getCategorizedObject() instanceof AbstractSetting)
.filter((Categorization c) .filter((Categorization c)
-> ((AbstractSetting<?>) c.getCategorizedObject()) -> ((AbstractSetting<?>) c.getCategorizedObject())
.getName() .getName()
.equals(tokens[tokens.length - 1])) .equals(tokens[tokens.length - 1]))
.findFirst(); .findFirst();
if (result.isPresent()) { if (result.isPresent()) {
final CcmObject object = result.get().getCategorizedObject(); final CcmObject object = result.get().getCategorizedObject();
@ -403,20 +415,20 @@ public class ConfigurationManager {
if (clazz.isInstance(entry.getValue())) { if (clazz.isInstance(entry.getValue())) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final AbstractSetting<T> resultEntry final AbstractSetting<T> resultEntry
= (AbstractSetting<T>) entry; = (AbstractSetting<T>) entry;
return resultEntry; return resultEntry;
} else { } else {
LOGGER.warn(String.format("Setting \"%s\" found but is not of " LOGGER.warn(String.format("Setting \"%s\" found but is not of "
+ "the requested type \"%s\".", + "the requested type \"%s\".",
name, name,
clazz.getName())); clazz.getName()));
return null; return null;
} }
} else { } else {
LOGGER.warn(String.format( LOGGER.warn(String.format(
"Setting \"%s\" was not found in category \"%s\".", "Setting \"%s\" was not found in category \"%s\".",
name, name,
categoryPath)); categoryPath));
return null; return null;
} }
} }
@ -443,9 +455,12 @@ public class ConfigurationManager {
* @param field The setting field. * @param field The setting field.
* *
* @return The name of the field or if the {@link Setting} annotation of the * @return The name of the field or if the {@link Setting} annotation of the
* field has a name value, the value of that field. * field has a name value, the value of that field.
*/ */
private String getSettingName(final Field field) { private String getSettingName(final Field field) {
LOGGER.debug(String.format("Trying to get setting name from field: "
+ "\"%s\"",
field.getName()));
final Setting annotation = field.getAnnotation(Setting.class); final Setting annotation = field.getAnnotation(Setting.class);
if (annotation.name() == null || annotation.name().isEmpty()) { if (annotation.name() == null || annotation.name().isEmpty()) {
@ -458,17 +473,17 @@ public class ConfigurationManager {
/** /**
* Create a setting instance of a specific value type. * Create a setting instance of a specific value type.
* *
* @param <T> Type variable. * @param <T> Type variable.
* @param valueType The type of the value of the setting to create. * @param valueType The type of the value of the setting to create.
* *
* @return An setting instance of the provided value type. * @return An setting instance of the provided value type.
* *
* @throws IllegalArgumentException If there is not setting type for the * @throws IllegalArgumentException If there is not setting type for the
* provided value type. * provided value type.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private <T> AbstractSetting<T> createSettingForValueType( private <T> AbstractSetting<T> createSettingForValueType(
final Class<T> valueType) { final Class<T> valueType) {
final String valueTypeName = valueType.getName(); final String valueTypeName = valueType.getName();
if (BigDecimal.class.getName().equals(valueTypeName)) { if (BigDecimal.class.getName().equals(valueTypeName)) {
@ -487,54 +502,78 @@ public class ConfigurationManager {
return (AbstractSetting<T>) new StringSetting(); return (AbstractSetting<T>) new StringSetting();
} else { } else {
throw new IllegalArgumentException(String.format( throw new IllegalArgumentException(String.format(
"No setting type for value type \"s\".", valueTypeName)); "No setting type for value type \"s\".", valueTypeName));
} }
} }
/** /**
* Sets a value on a setting in the registry. * Sets a value on a setting in the registry.
* *
* @param <T> The value type of the setting. * @param <T> The value type of the setting.
* @param configuration The configuration to which the settings belongs. * @param configuration The configuration to which the settings belongs.
* @param settingName The name of the setting. * @param settingName The name of the setting.
* @param valueType The type of the value of the setting. * @param valueType The type of the value of the setting.
* @param value The value to set. * @param value The value to set.
*/ */
private <T> void setSettingValue(final Object configuration, private <T> void setSettingValue(final Object configuration,
final String settingName, final String settingName,
final Class<T> valueType, final Class<T> valueType,
final Object value) { final Object value) {
final String settingPath = String.format( final String settingPath = String.format(
"%s.%s", "%s.%s",
configuration.getClass().getName(), configuration.getClass().getName(),
settingName); settingName);
LOGGER.debug(String.format("Saving setting \"%s\"...", settingPath));
AbstractSetting<T> setting = findSetting(settingPath, valueType); AbstractSetting<T> setting = findSetting(settingPath, valueType);
if (setting == null) { if (setting == null) {
LOGGER.debug(String.format("Setting \"%s\" does not yet exist in "
+ "database. Creating new setting.",
settingPath));
setting = createSettingForValueType(valueType); setting = createSettingForValueType(valueType);
setting.setName(settingName); setting.setName(settingName);
final Domain registry = domainRepository final Domain registry = domainRepository
.findByDomainKey(REGISTRY_DOMAIN); .findByDomainKey(REGISTRY_DOMAIN);
final Category category = categoryRepository Category category = categoryRepository
.findByPath(registry, configuration.getClass().getName()); .findByPath(registry, configuration.getClass().getName());
if (category == null) {
final String[] tokens = configuration.getClass().getName().
split("\\.");
final StringBuilder categoryPath = new StringBuilder(
configuration.getClass().getName().length());
for (String token : tokens) {
if (categoryPath.length() > 0) {
categoryPath.append('.');
}
categoryPath.append(token);
category = createCategoryIfNotExists(categoryPath.toString());
}
}
categoryManager.addObjectToCategory(setting, category); categoryManager.addObjectToCategory(setting, category);
} }
LOGGER.debug(String.format("New value of setting \"%s\" is: \"%s\"",
settingPath,
value.toString()));
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final T settingValue = (T) value; final T settingValue = (T) value;
setting.setValue(settingValue); setting.setValue(settingValue);
LOGGER.debug(String.format("Value of setting \"%s\" is now: \"%s\"",
settingPath,
setting.getValue().toString()));
LOGGER.debug("Saving changed setting to DB...");
entityManager.merge(setting); entityManager.merge(setting);
} }
/** /**
* Sets the value of a setting of application instance configuration. * Sets the value of a setting of application instance configuration.
* *
* @param <T> The value type of the setting. * @param <T> The value type of the setting.
* @param configuration The configuration to which the settings belongs. * @param configuration The configuration to which the settings belongs.
* @param instance The application instance to which * @param instance The application instance to which
* @param settingName The name of the setting. * @param settingName The name of the setting.
* @param valueType The type of the value of the setting. * @param valueType The type of the value of the setting.
* @param value The value to set. * @param value The value to set.
*/ */
private <T> void setSettingValue(final Object configuration, private <T> void setSettingValue(final Object configuration,
final CcmApplication instance, final CcmApplication instance,
@ -542,18 +581,18 @@ public class ConfigurationManager {
final Class<T> valueType, final Class<T> valueType,
final Object value) { final Object value) {
final String settingPath = String.format( final String settingPath = String.format(
"%s.%s.%s", "%s.%s.%s",
configuration.getClass().getName(), configuration.getClass().getName(),
instance.getPrimaryUrl(), instance.getPrimaryUrl(),
settingName); settingName);
AbstractSetting<T> setting = findSetting(settingPath, valueType); AbstractSetting<T> setting = findSetting(settingPath, valueType);
if (setting == null) { if (setting == null) {
setting = createSettingForValueType(valueType); setting = createSettingForValueType(valueType);
setting.setName(settingName); setting.setName(settingName);
final Domain registry = domainRepository final Domain registry = domainRepository
.findByDomainKey(REGISTRY_DOMAIN); .findByDomainKey(REGISTRY_DOMAIN);
final Category category = categoryRepository final Category category = categoryRepository
.findByPath(registry, configuration.getClass().getName()); .findByPath(registry, configuration.getClass().getName());
categoryManager.addObjectToCategory(setting, category); categoryManager.addObjectToCategory(setting, category);
} }
@ -567,23 +606,21 @@ public class ConfigurationManager {
/** /**
* Helper method for loading a configuration from the registry. * Helper method for loading a configuration from the registry.
* *
* @param <T> The type of the configuration. * @param <T> The type of the configuration.
* @param confName The fully qualified name of the configuration in the * @param confName The fully qualified name of the configuration in the
* registry. For normal configuration this is the fully * registry. For normal configuration this is the fully qualified name of
* qualified name of the configuration class. For * the configuration class. For application instance configurations this is
* application instance configurations this is the fully * the fully qualified name of the configuration class joined with the
* qualified name of the configuration class joined with * primary URL of the application instance, separated with a dot.
* the primary URL of the application instance, separated
* with a dot.
* @param confClass The configuration class. * @param confClass The configuration class.
* *
* @return An instance of the configuration class with all setting fields * @return An instance of the configuration class with all setting fields
* set to the values stored in the registry. * set to the values stored in the registry.
*/ */
private <T> T findConfiguration(final String confName, private <T> T findConfiguration(final String confName,
final Class<T> confClass) { final Class<T> confClass) {
final Domain registry = domainRepository final Domain registry = domainRepository
.findByDomainKey(REGISTRY_DOMAIN); .findByDomainKey(REGISTRY_DOMAIN);
final Category category = categoryRepository.findByPath(registry, final Category category = categoryRepository.findByPath(registry,
confName); confName);
@ -596,8 +633,8 @@ public class ConfigurationManager {
conf = confClass.newInstance(); conf = confClass.newInstance();
} catch (InstantiationException | IllegalAccessException ex) { } catch (InstantiationException | IllegalAccessException ex) {
LOGGER.warn(String.format( LOGGER.warn(String.format(
"Failed to instantiate configuration \"%s\".", "Failed to instantiate configuration \"%s\".",
confClass.getName()), confClass.getName()),
ex); ex);
return null; return null;
} }
@ -617,15 +654,16 @@ public class ConfigurationManager {
settingType); settingType);
if (setting != null) { if (setting != null) {
try { try {
LOGGER.debug("Setting \"%s\" found. Value: %s", LOGGER.debug(String.
settingPath, format("Setting \"%s\" found. Value: %s",
setting.getValue().toString()); settingPath,
setting.getValue().toString()));
field.set(conf, setting.getValue()); field.set(conf, setting.getValue());
} catch (IllegalAccessException ex) { } catch (IllegalAccessException ex) {
LOGGER.warn(String.format( LOGGER.warn(String.format(
"Failed to set value of configuration class \"%s\". " "Failed to set value of configuration class \"%s\". "
+ "Ignoring.", + "Ignoring.",
confClass.getName()), confClass.getName()),
ex); ex);
} }
} }
@ -634,4 +672,61 @@ public class ConfigurationManager {
return conf; return conf;
} }
private Category createCategoryIfNotExists(final String categoryPath) {
LOGGER.debug(String.format("Checking if category \"%s\" exists. If not "
+ "the category will be created.",
categoryPath));
final Domain registry = domainRepository.
findByDomainKey(REGISTRY_DOMAIN);
final Category root = registry.getRoot();
final String[] tokens = categoryPath.split("\\.");
Category category = categoryRepository.findByPath(registry,
categoryPath);
if (category == null) {
LOGGER.debug(String.format(
"Category \"%s\" was not found. Creating category.",
categoryPath));
category = new Category();
category.setName(tokens[tokens.length - 1]);
category.setUniqueId(UUID.randomUUID().toString());
category.setEnabled(true);
category.setVisible(true);
category.setAbstractCategory(false);
if (tokens.length > 1) {
final StringBuilder parentPath = new StringBuilder();
for (int i = 0; i < tokens.length - 1; i++) {
if (i > 0) {
parentPath.append('.');
}
parentPath.append(tokens);
}
final Category parent = categoryRepository.findByPath(
registry,
parentPath.toString());
if (parent == null) {
throw new IllegalStateException(String.format(
"Parent category \"%s\" of for new category \"%s\" does"
+ "not exist, but should. Can't continue.",
parentPath.toString(),
categoryPath));
}
categoryManager.addSubCategoryToCategory(category, parent);
LOGGER.debug(new FormattedMessage(
"Created category \"%s\" as child of category \"%s\".",
categoryPath,
parent.getName()));
} else {
categoryManager.addSubCategoryToCategory(category, root);
LOGGER.debug(new FormattedMessage(
"Created category \"%s\" as child of the registry root "
+ "category.",
categoryPath));
}
}
return category;
}
} }

View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2015 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 com.example;
import org.libreccm.configuration.Configuration;
import org.libreccm.configuration.Setting;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Configuration
public class TestConfiguration {
@Setting
private Boolean enabled = false;
@Setting
private Long itemsPerPage = 40L;
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(final Boolean enabled) {
this.enabled = enabled;
}
public Long getItemsPerPage() {
return itemsPerPage;
}
public void setItemsPerPage(final Long itemsPerPage) {
this.itemsPerPage = itemsPerPage;
}
}

View File

@ -18,6 +18,7 @@
*/ */
package org.libreccm.configuration; package org.libreccm.configuration;
import com.example.TestConfiguration;
import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.junit.InSequence; import org.jboss.arquillian.junit.InSequence;
@ -52,6 +53,7 @@ import java.io.File;
import java.math.BigDecimal; import java.math.BigDecimal;
import javax.inject.Inject; import javax.inject.Inject;
import org.jboss.arquillian.persistence.ShouldMatchDataSet;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@ -92,10 +94,10 @@ public class ConfigurationManagerTest {
@Deployment @Deployment
public static WebArchive createDeployment() { public static WebArchive createDeployment() {
final PomEquippedResolveStage pom = Maven final PomEquippedResolveStage pom = Maven
.resolver() .resolver()
.loadPomFromFile("pom.xml"); .loadPomFromFile("pom.xml");
final PomEquippedResolveStage dependencies = pom final PomEquippedResolveStage dependencies = pom
.importCompileAndRuntimeDependencies(); .importCompileAndRuntimeDependencies();
final File[] libs = dependencies.resolve().withTransitivity().asFile(); final File[] libs = dependencies.resolve().withTransitivity().asFile();
for (File lib : libs) { for (File lib : libs) {
@ -104,28 +106,29 @@ public class ConfigurationManagerTest {
} }
return ShrinkWrap return ShrinkWrap
.create(WebArchive.class, .create(WebArchive.class,
"LibreCCM-org.libreccm.categorization.CategoryManagerTest.war") "LibreCCM-org.libreccm.categorization.CategoryManagerTest.war").
.addPackage(CcmObject.class.getPackage()) addPackage(CcmObject.class.getPackage())
.addPackage(Permission.class.getPackage()) .addPackage(Permission.class.getPackage())
.addPackage(CcmApplication.class.getPackage()) .addPackage(CcmApplication.class.getPackage())
.addPackage(Categorization.class.getPackage()) .addPackage(Categorization.class.getPackage())
.addPackage(Configuration.class.getPackage()) .addPackage(Configuration.class.getPackage())
.addPackage(LocalizedString.class.getPackage()) .addPackage(LocalizedString.class.getPackage())
.addPackage(Workflow.class.getPackage()) .addPackage(Workflow.class.getPackage())
.addPackage(EntityManagerProducer.class.getPackage()) .addPackage(EntityManagerProducer.class.getPackage())
.addPackage(MimeTypeConverter.class.getPackage()) .addPackage(MimeTypeConverter.class.getPackage())
.addPackage(EqualsVerifier.class.getPackage()) .addPackage(EqualsVerifier.class.getPackage())
.addPackage(IntegrationTest.class.getPackage()) .addPackage(IntegrationTest.class.getPackage())
.addAsLibraries(libs) .addPackage(TestConfiguration.class.getPackage())
.addAsResource("test-persistence.xml", .addAsLibraries(libs)
"META-INF/persistence.xml") .addAsResource("test-persistence.xml",
.addAsResource( "META-INF/persistence.xml")
"configs/org/libreccm/configuration/ConfigurationManagerTest/" .addAsResource(
+ "log4j2.xml", "configs/org/libreccm/configuration/ConfigurationManagerTest/"
"log4j2.xml") + "log4j2.xml",
.addAsWebInfResource("test-web.xml", "WEB-INF/web.xml") "log4j2.xml")
.addAsWebInfResource(EmptyAsset.INSTANCE, "WEB-INF/beans.xml"); .addAsWebInfResource("test-web.xml", "WEB-INF/web.xml")
.addAsWebInfResource(EmptyAsset.INSTANCE, "WEB-INF/beans.xml");
} }
@Test @Test
@ -136,7 +139,7 @@ public class ConfigurationManagerTest {
@Test @Test
@UsingDataSet( @UsingDataSet(
"datasets/org/libreccm/configuration/ConfigurationManagerTest/data.yml") "datasets/org/libreccm/configuration/ConfigurationManagerTest/data.yml")
@InSequence(2) @InSequence(2)
public void datasetOnly() { public void datasetOnly() {
System.out.println("Dataset loaded successfully."); System.out.println("Dataset loaded successfully.");
@ -144,12 +147,13 @@ public class ConfigurationManagerTest {
@Test @Test
@UsingDataSet( @UsingDataSet(
"datasets/org/libreccm/configuration/ConfigurationManagerTest/data.yml") "datasets/org/libreccm/configuration/ConfigurationManagerTest/data.yml")
@InSequence(1100) @InSequence(1100)
public void loadConfiguration() { public void loadConfiguration() {
final ExampleConfiguration configuration = configurationManager final ExampleConfiguration configuration = configurationManager
.findConfiguration(ExampleConfiguration.class); .findConfiguration(ExampleConfiguration.class);
assertThat(configuration, is(not(nullValue())));
assertThat(configuration.getPrice(), assertThat(configuration.getPrice(),
is(equalTo(new BigDecimal("98.99")))); is(equalTo(new BigDecimal("98.99"))));
assertThat(configuration.isEnabled(), is(true)); assertThat(configuration.isEnabled(), is(true));
@ -159,4 +163,43 @@ public class ConfigurationManagerTest {
is(equalTo("http://www.example.org"))); is(equalTo("http://www.example.org")));
} }
@Test
@UsingDataSet(
"datasets/org/libreccm/configuration/ConfigurationManagerTest/data.yml")
@ShouldMatchDataSet(
"datasets/org/libreccm/configuration/ConfigurationManagerTest/"
+ "after-save-changed.yml")
@InSequence(1200)
public void saveConfiguration() {
final ExampleConfiguration configuration = configurationManager
.findConfiguration(ExampleConfiguration.class);
configuration.setPrice(new BigDecimal("109.99"));
configuration.setItemsPerPage(30L);
configurationManager.saveConfiguration(configuration);
}
@Test
@UsingDataSet(
"datasets/org/libreccm/configuration/ConfigurationManagerTest/data.yml")
@InSequence(2100)
public void loadNewConfiguration() {
final TestConfiguration configuration = configurationManager
.findConfiguration(TestConfiguration.class);
assertThat(configuration, is(nullValue()));
}
@Test
@UsingDataSet(
"datasets/org/libreccm/configuration/ConfigurationManagerTest/data.yml")
@ShouldMatchDataSet(
"datasets/org/libreccm/configuration/ConfigurationManagerTest/"
+ "after-save-new.yml")
@InSequence(2200)
public void saveNewConfiguration() {
configurationManager.saveConfiguration(new TestConfiguration());
}
} }

View File

@ -45,6 +45,8 @@ public class DatasetsTest extends DatasetsVerifier {
@Parameterized.Parameters(name = "Dataset {0}") @Parameterized.Parameters(name = "Dataset {0}")
public static Collection<String> data() { public static Collection<String> data() {
return Arrays.asList(new String[]{ return Arrays.asList(new String[]{
"/datasets/org/libreccm/configuration/ConfigurationManagerTest/after-save-changed.yml",
"/datasets/org/libreccm/configuration/ConfigurationManagerTest/after-save-new.yml",
"/datasets/org/libreccm/configuration/ConfigurationManagerTest/data.yml"}); "/datasets/org/libreccm/configuration/ConfigurationManagerTest/data.yml"});
} }

View File

@ -81,7 +81,4 @@ public class ExampleConfiguration {
public void setHelpUrl(final String helpUrl) { public void setHelpUrl(final String helpUrl) {
this.helpUrl = helpUrl; this.helpUrl = helpUrl;
} }
} }

View File

@ -13,5 +13,9 @@
level="debug"> level="debug">
<AppenderRef ref="Console"/> <AppenderRef ref="Console"/>
</Logger> </Logger>
<Logger name="org.libreccm.categorization.CategoryRepository"
level="debug">
<AppenderRef ref="Console"/>
</Logger>
</Loggers> </Loggers>
</Configuration> </Configuration>

View File

@ -0,0 +1,135 @@
ccm_core.ccm_objects:
- object_id: -1000
display_name: registry
- object_id: -2000
display_name: registry_root
- object_id: -2100
display_name: org
- object_id: -2200
display_name: libreccm
- object_id: -2300
display_name: configuration
- object_id: -2400
display_name: ExampleConfiguration
- object_id: -3100
display_name: price
- object_id: -3200
display_name: enabled
- object_id: -3300
display_name: minTemperature
- object_id: -3400
display_name: itemsPerPage
- object_id: -3500
display_name: helpUri
ccm_core.categories:
- object_id: -2000
unique_id: bb93a964-bf66-424c-a22d-074d001db3b8
name: registry-root
enabled: true
visible: true
abstract_category: false
category_order: 0
- object_id: -2100
unique_id: 62c22973-a078-47bc-8267-bef879c7566e
name: org
enabled: true
visible: true
abstract_category: false
parent_category_id: -2000
category_order: 1
- object_id: -2200
unique_id: a8fbf310-7cb9-47dd-81d5-a16b80e96446
name: libreccm
enabled: true
visible: true
abstract_category: false
parent_category_id: -2100
category_order: 1
- object_id: -2300
unique_id: 61c30c73-857a-49ff-8272-c9fb038d3e35
name: configuration
enabled: true
visible: true
abstract_category: false
parent_category_id: -2200
category_order: 1
- object_id: -2400
unique_id: bf5d295c-6ad3-4484-a1e6-5641cea037b3
name: ExampleConfiguration
enabled: true
visible: true
abstract_category: false
parent_category_id: -2300
category_order: 1
ccm_core.category_domains:
- object_id: -1000
domain_key: registry
root_category_id: -2000
version: 1.0
ccm_core.categorizations:
- categorization_id: -10100
category_id: -2400
object_id: -3100
category_order: 1
object_order: 1
category_index: false
- categorization_id: -10200
category_id: -2400
object_id: -3200
category_order: 1
object_order: 2
category_index: false
- categorization_id: -10300
category_id: -2400
object_id: -3300
category_order: 1
object_order: 3
category_index: false
- categorization_id: -10400
category_id: -2400
object_id: -3400
category_order: 1
object_order: 4
category_index: false
- categorization_id: -10500
category_id: -2400
object_id: -3500
category_order: 1
object_order: 5
category_index: false
ccm_core.settings:
- object_id: -3100
name: price
- object_id: -3200
name: enabled
- object_id: -3300
name: minTemperature
- object_id: -3400
name: itemsPerPage
- object_id: -3500
name: helpUrl
ccm_core.settings_big_decimal:
- object_id: -3100
setting_value: 109.99
ccm_core.settings_boolean:
- object_id: -3200
setting_value: true
ccm_core.settings_double:
- object_id: -3300
setting_value: 23.5
ccm_core.settings_long:
- object_id: -3400
setting_value: 30
ccm_core.settings_string:
- object_id: -3500
setting_value: http://www.example.org

View File

@ -0,0 +1,177 @@
ccm_core.ccm_objects:
- object_id: -1000
display_name: registry
- object_id: -2000
display_name: registry_root
- object_id: -2100
display_name: org
- object_id: -2200
display_name: libreccm
- object_id: -2300
display_name: configuration
- object_id: -2400
display_name: ExampleConfiguration
- object_id: -3100
display_name: price
- object_id: -3200
display_name: enabled
- object_id: -3300
display_name: minTemperature
- object_id: -3400
display_name: itemsPerPage
- object_id: -3500
display_name: helpUri
- object_id: -2500
display_name: com
- object_id: -2600
display_name: example
- object_id: -2700
display_name: TestConfiguration
- object_id: -3600
display_name: enabled
- object_id: -3700
display_name: itemsPerPage
ccm_core.categories:
- object_id: -2000
unique_id: bb93a964-bf66-424c-a22d-074d001db3b8
name: registry-root
enabled: true
visible: true
abstract_category: false
category_order: 0
- object_id: -2100
unique_id: 62c22973-a078-47bc-8267-bef879c7566e
name: org
enabled: true
visible: true
abstract_category: false
parent_category_id: -2000
category_order: 1
- object_id: -2200
unique_id: a8fbf310-7cb9-47dd-81d5-a16b80e96446
name: libreccm
enabled: true
visible: true
abstract_category: false
parent_category_id: -2100
category_order: 1
- object_id: -2300
unique_id: 61c30c73-857a-49ff-8272-c9fb038d3e35
name: configuration
enabled: true
visible: true
abstract_category: false
parent_category_id: -2200
category_order: 1
- object_id: -2400
unique_id: bf5d295c-6ad3-4484-a1e6-5641cea037b3
name: ExampleConfiguration
enabled: true
visible: true
abstract_category: false
parent_category_id: -2300
category_order: 1
- object_id: -2500
unique_id: 36223799-5df7-4875-8191-f1ced0965237
name: com
enabled: true
visible: true
abstract_category: false
parent_category_id: -2000
category_order: 1
- object_id: -2600
unique_id: 22f6f7c6-2ca1-457b-9b3f-185a2c6f39be
name: example
enabled: true
visible: true
abstract_category: false
parent_category_id: -2500
category_order: 1
- object_id: -2700
unique_id: af6c0e93-d60b-4c5f-8fe4-5f82a7f8f923
name: TestConfiguration
enabled: true
visible: true
abstract_category: false
parent_category_id: -2600
category_order: 1
ccm_core.category_domains:
- object_id: -1000
domain_key: registry
root_category_id: -2000
version: 1.0
ccm_core.categorizations:
- categorization_id: -10100
category_id: -2400
object_id: -3100
category_order: 1
object_order: 1
category_index: false
- categorization_id: -10200
category_id: -2400
object_id: -3200
category_order: 1
object_order: 2
category_index: false
- categorization_id: -10300
category_id: -2400
object_id: -3300
category_order: 1
object_order: 3
category_index: false
- categorization_id: -10400
category_id: -2400
object_id: -3400
category_order: 1
object_order: 4
category_index: false
- categorization_id: -10500
category_id: -2400
object_id: -3500
category_order: 1
object_order: 5
category_index: false
ccm_core.settings:
- object_id: -3100
name: price
- object_id: -3200
name: enabled
- object_id: -3300
name: minTemperature
- object_id: -3400
name: itemsPerPage
- object_id: -3500
name: helpUrl
- object_id: -3600
name: enabled
- object_id: -3700
name: itemsPerPage
ccm_core.settings_big_decimal:
- object_id: -3100
setting_value: 98.99
ccm_core.settings_boolean:
- object_id: -3200
setting_value: true
- object_id: -3600
setting_value: false
ccm_core.settings_double:
- object_id: -3300
setting_value: 23.5
ccm_core.settings_long:
- object_id: -3400
setting_value: 20
- object_id: -3700
setting_value: 40
ccm_core.settings_string:
- object_id: -3500
setting_value: http://www.example.org