diff --git a/ccm-core/src/main/java/org/libreccm/categorization/Category.java b/ccm-core/src/main/java/org/libreccm/categorization/Category.java index f7f394327..a525e6e0a 100644 --- a/ccm-core/src/main/java/org/libreccm/categorization/Category.java +++ b/ccm-core/src/main/java/org/libreccm/categorization/Category.java @@ -76,7 +76,7 @@ public class Category extends CcmObject implements Serializable { * A unique ID for the category. This ID will be the same even the same * category system/domain is used in different installations. */ - @Column(name = "UNIQUE_ID", nullable = false) + @Column(name = "UNIQUE_ID") private String uniqueId; /** @@ -371,8 +371,7 @@ public class Category extends CcmObject implements Serializable { + "title = %s, " + "enabled = %b, " + "visible = %b, " - + "abstractCategory = %b, " - + "parentCategory = %s, " + + "abstractCategory = %s, " + "categoryOrder = %d%s", uniqueId, name, @@ -380,7 +379,6 @@ public class Category extends CcmObject implements Serializable { enabled, visible, abstractCategory, - Objects.toString(parentCategory), categoryOrder, data)); } diff --git a/ccm-core/src/main/java/org/libreccm/categorization/CategoryRepository.java b/ccm-core/src/main/java/org/libreccm/categorization/CategoryRepository.java index 4f1526dfc..66d50f4f7 100644 --- a/ccm-core/src/main/java/org/libreccm/categorization/CategoryRepository.java +++ b/ccm-core/src/main/java/org/libreccm/categorization/CategoryRepository.java @@ -27,8 +27,10 @@ import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.persistence.NoResultException; import javax.persistence.TypedQuery; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.message.FormattedMessage; /** * @@ -124,9 +126,18 @@ public class CategoryRepository extends AbstractEntityRepository final String[] tokens = normalizedPath.split("/"); Category current = domain.getRoot(); for (String token : tokens) { + if (current.getSubCategories() == null) { + LOGGER.error(new FormattedMessage("#findByPath(Domain, String): current category \"%s\" has no sub categories", current.getName())); + } final Optional result = current.getSubCategories() .stream() .filter((c) -> { + LOGGER.debug(new FormattedMessage( + "#findByPath(Domain, String): c = %s", c.toString())); + LOGGER.debug(new FormattedMessage( + "#findByPath(Domain, String): c.getName = \"%s\"", c.getName())); + LOGGER.debug(new FormattedMessage( + "#findByPath(Domain, String): token = \"%s\"", token)); return c.getName().equals(token); }) .findFirst(); diff --git a/ccm-core/src/main/java/org/libreccm/configuration/ConfigurationManager.java b/ccm-core/src/main/java/org/libreccm/configuration/ConfigurationManager.java index 0b8e7c1c2..cbd33f56b 100644 --- a/ccm-core/src/main/java/org/libreccm/configuration/ConfigurationManager.java +++ b/ccm-core/src/main/java/org/libreccm/configuration/ConfigurationManager.java @@ -43,8 +43,15 @@ import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.UUID; + import org.apache.logging.log4j.message.FormattedMessage; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.StringJoiner; + /** * Maps between configuration classes and the values stored in the registry. * @@ -54,7 +61,7 @@ import org.apache.logging.log4j.message.FormattedMessage; public class ConfigurationManager { private static final Logger LOGGER = LogManager.getLogger( - ConfigurationManager.class); + ConfigurationManager.class); @Inject private CategoryManager categoryManager; @@ -71,11 +78,11 @@ public class ConfigurationManager { /** * Load all settings of the provided configuration class. * - * @param Type of the configuration class. + * @param Type of the configuration class. * @param confClass The configuration class. * * @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 findConfiguration(final Class confClass) { if (confClass == null) { @@ -84,9 +91,9 @@ public class ConfigurationManager { if (confClass.getAnnotation(Configuration.class) == null) { throw new IllegalArgumentException(String.format( - "Provided class \"%s\" is not annotated with \"%s\".", - confClass.getName(), - Configuration.class.getName())); + "Provided class \"%s\" is not annotated with \"%s\".", + confClass.getName(), + Configuration.class.getName())); } final String confName = confClass.getName(); @@ -99,11 +106,13 @@ public class ConfigurationManager { * registry. * * @param configuration The configuration to save. The class of the provided - * object must be annotation with {@link Configuration}. + * object must be annotation with + * {@link Configuration}. * * @throws IllegalArgumentException If the {@code configuration} parameter - * is {@code null} or if the class of the provided object is not annotation - * with {@link Configuration}. + * is {@code null} or if the class of the + * provided object is not annotation with + * {@link Configuration}. */ public void saveConfiguration(final Object configuration) { if (configuration == null) { @@ -112,10 +121,10 @@ public class ConfigurationManager { 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())); + "The class \"%s\" of the provided object is not annotated " + + "with \"%s\".", + configuration.getClass().getName(), + Configuration.class.getName())); } LOGGER.debug(String.format("Saving configuration \"%s\"...", @@ -126,10 +135,10 @@ public class ConfigurationManager { 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())); + "Field \"%s\" of class \"%s\" is not " + + "a setting. Ignoring it.", + configuration.getClass().getName(), + field.getName())); continue; } @@ -140,16 +149,16 @@ public class ConfigurationManager { 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()), + "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()), + "Failed to write setting value for setting \"%s\" " + + "of configuration \"%s\"", + getSettingName(field), + configuration.getClass().getName()), ex); } } @@ -159,15 +168,15 @@ public class ConfigurationManager { * Finds an application instance specific configuration and loads it values * from the registry. * - * @param The type of the configuration. + * @param The type of the configuration. * @param confClass The configuration class. - * @param instance The application instance for which the settings are - * loaded. + * @param instance The application instance for which the settings are + * loaded. * * @return The configuration for the provided application instance. */ public T findConfiguration( - final Class confClass, final CcmApplication instance) { + final Class confClass, final CcmApplication instance) { if (confClass == null) { throw new IllegalArgumentException("confClass can't be null"); } @@ -178,9 +187,9 @@ public class ConfigurationManager { if (confClass.getAnnotation(Configuration.class) == null) { throw new IllegalArgumentException(String.format( - "Provided class \"%s\" is not annotated with \"%s\".", - confClass.getName(), - Configuration.class.getName())); + "Provided class \"%s\" is not annotated with \"%s\".", + confClass.getName(), + Configuration.class.getName())); } final String confName = String.format("%s.%s", @@ -194,8 +203,8 @@ public class ConfigurationManager { * Saves a application instance configuration. * * @param configuration The configuration to save. - * @param instance The application instance of which the configuration - * stores the settings. + * @param instance The application instance of which the configuration + * stores the settings. */ public void saveConfiguration(final ApplicationConfiguration configuration, final CcmApplication instance) { @@ -205,10 +214,10 @@ public class ConfigurationManager { 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())); + "The class \"%s\" of the provided object is not annotated " + + "with \"%s\".", + configuration.getClass().getName(), + Configuration.class.getName())); } if (instance == null) { @@ -226,16 +235,16 @@ public class ConfigurationManager { 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()), + "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()), + "Failed to write setting value for setting \"%s\" " + + "of configuration \"%s\"", + getSettingName(field), + configuration.getClass().getName()), ex); } } @@ -247,7 +256,7 @@ public class ConfigurationManager { * @param configuration The configuration for which the info is generated. * * @return a {@link ConfigurationInfo} instance describing the provided - * configuration. + * configuration. */ public ConfigurationInfo getConfigurationInfo(final Class configuration) { if (configuration == null) { @@ -256,14 +265,14 @@ public class ConfigurationManager { 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())); + "The class \"%s\" of the provided object is not annotated " + + "with \"%s\".", + configuration.getClass().getName(), + Configuration.class.getName())); } final Configuration annotation = configuration.getAnnotation( - Configuration.class); + Configuration.class); final ConfigurationInfo confInfo = new ConfigurationInfo(); confInfo.setName(configuration.getClass().getName()); @@ -286,9 +295,9 @@ public class ConfigurationManager { * 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. + * belongs. + * @param name The name of the setting for which the + * {@link SettingInfo} is generated. * * @return The {@link SettingInfo} for the provided configuration class. */ @@ -300,14 +309,14 @@ public class ConfigurationManager { 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())); + "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); + Configuration.class); final String descBundle = confAnnotation.descBundle(); final Field field; @@ -315,10 +324,10 @@ public class ConfigurationManager { 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), + "Failed to generate SettingInfo for field \"%s\" of " + + "configuration \"%s\". Ignoring field.", + configuration.getClass().getName(), + name), ex); return null; } @@ -330,7 +339,7 @@ public class ConfigurationManager { final Setting settingAnnotation = field.getAnnotation(Setting.class); final SettingInfo settingInfo = new SettingInfo(); if (settingAnnotation.name() == null - || settingAnnotation.name().isEmpty()) { + || settingAnnotation.name().isEmpty()) { settingInfo.setName(field.getName()); } else { settingInfo.setName(settingAnnotation.name()); @@ -343,7 +352,7 @@ public class ConfigurationManager { settingInfo.setDefaultValue(field.get(conf).toString()); } catch (InstantiationException | IllegalAccessException ex) { LOGGER.warn(String.format("Failed to create instance of \"%s\" to " - + "get default values.", + + "get default values.", configuration.getName()), ex); } @@ -359,19 +368,19 @@ public class ConfigurationManager { /** * A low level method for finding a setting in the registry. * - * @param Type of the value of the setting - * @param name The fully qualified name of the setting. + * @param 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. + * otherwise. */ public AbstractSetting findSetting(final String name, final Class clazz) { LOGGER.debug(String.format( - "Trying to find setting \"%s\" of type \"%s\"", - name, - clazz.getName())); + "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, @@ -384,29 +393,29 @@ public class ConfigurationManager { categoryPath)); final Domain registry = domainRepository - .findByDomainKey(REGISTRY_DOMAIN); + .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))); + "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 result = category - .getObjects() - .stream() - .filter((Categorization c) - -> c.getCategorizedObject() instanceof AbstractSetting) - .filter((Categorization c) - -> ((AbstractSetting) c.getCategorizedObject()) - .getName() - .equals(tokens[tokens.length - 1])) - .findFirst(); + .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(); @@ -415,20 +424,20 @@ public class ConfigurationManager { if (clazz.isInstance(entry.getValue())) { @SuppressWarnings("unchecked") final AbstractSetting resultEntry - = (AbstractSetting) entry; + = (AbstractSetting) entry; return resultEntry; } else { LOGGER.warn(String.format("Setting \"%s\" found but is not of " - + "the requested type \"%s\".", + + "the requested type \"%s\".", name, clazz.getName())); return null; } } else { LOGGER.warn(String.format( - "Setting \"%s\" was not found in category \"%s\".", - name, - categoryPath)); + "Setting \"%s\" was not found in category \"%s\".", + name, + categoryPath)); return null; } } @@ -455,11 +464,11 @@ public class ConfigurationManager { * @param field The setting field. * * @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) { LOGGER.debug(String.format("Trying to get setting name from field: " - + "\"%s\"", + + "\"%s\"", field.getName())); final Setting annotation = field.getAnnotation(Setting.class); @@ -473,17 +482,17 @@ public class ConfigurationManager { /** * Create a setting instance of a specific value type. * - * @param Type variable. + * @param 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. + * provided value type. */ @SuppressWarnings("unchecked") private AbstractSetting createSettingForValueType( - final Class valueType) { + final Class valueType) { final String valueTypeName = valueType.getName(); if (BigDecimal.class.getName().equals(valueTypeName)) { @@ -496,59 +505,66 @@ public class ConfigurationManager { return (AbstractSetting) new EnumSetting(); } else if (LocalizedString.class.getName().equals(valueTypeName)) { return (AbstractSetting) new LocalizedStringSetting(); - } else if (LongSetting.class.getName().equals(valueTypeName)) { + } else if (Long.class.getName().equals(valueTypeName)) { return (AbstractSetting) new LongSetting(); } else if (String.class.getName().equals(valueTypeName)) { return (AbstractSetting) new StringSetting(); } else { 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. * - * @param The value type of the setting. + * @param The value type of the setting. * @param configuration The configuration to which the settings belongs. - * @param settingName The name of the setting. - * @param valueType The type of the value of the setting. - * @param value The value to set. + * @param settingName The name of the setting. + * @param valueType The type of the value of the setting. + * @param value The value to set. */ private void setSettingValue(final Object configuration, final String settingName, final Class valueType, final Object value) { final String settingPath = String.format( - "%s.%s", - configuration.getClass().getName(), - settingName); - LOGGER.debug(String.format("Saving setting \"%s\"...", settingPath)); + "%s.%s", + configuration.getClass().getName(), + settingName); + LOGGER.debug(new FormattedMessage( + "Saving setting \"%s\" of type \"%s\"...", + settingPath, + valueType.getName())); AbstractSetting setting = findSetting(settingPath, valueType); if (setting == null) { LOGGER.debug(String.format("Setting \"%s\" does not yet exist in " - + "database. Creating new setting.", + + "database. Creating new setting.", settingPath)); setting = createSettingForValueType(valueType); setting.setName(settingName); - final Domain registry = domainRepository - .findByDomainKey(REGISTRY_DOMAIN); - Category category = categoryRepository - .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()); - } - } + setting.setDisplayName(settingName); + final Category category = findCategoryForNewSetting(configuration); categoryManager.addObjectToCategory(setting, category); + +// final Domain registry = domainRepository +// .findByDomainKey(REGISTRY_DOMAIN); +// Category category = categoryRepository +// .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); } LOGGER.debug(String.format("New value of setting \"%s\" is: \"%s\"", @@ -563,17 +579,18 @@ public class ConfigurationManager { LOGGER.debug("Saving changed setting to DB..."); entityManager.merge(setting); + entityManager.flush(); } /** * Sets the value of a setting of application instance configuration. * - * @param The value type of the setting. + * @param 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. + * @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 void setSettingValue(final Object configuration, final CcmApplication instance, @@ -581,18 +598,18 @@ public class ConfigurationManager { final Class valueType, final Object value) { final String settingPath = String.format( - "%s.%s.%s", - configuration.getClass().getName(), - instance.getPrimaryUrl(), - settingName); + "%s.%s.%s", + configuration.getClass().getName(), + instance.getPrimaryUrl(), + settingName); AbstractSetting setting = findSetting(settingPath, valueType); if (setting == null) { setting = createSettingForValueType(valueType); setting.setName(settingName); final Domain registry = domainRepository - .findByDomainKey(REGISTRY_DOMAIN); + .findByDomainKey(REGISTRY_DOMAIN); final Category category = categoryRepository - .findByPath(registry, configuration.getClass().getName()); + .findByPath(registry, configuration.getClass().getName()); categoryManager.addObjectToCategory(setting, category); } @@ -606,21 +623,23 @@ public class ConfigurationManager { /** * Helper method for loading a configuration from the registry. * - * @param The type of the configuration. - * @param confName The fully qualified name of the configuration in the - * registry. For normal configuration this is the fully qualified name of - * the configuration class. For application instance configurations this is - * the fully qualified name of the configuration class joined with the - * primary URL of the application instance, separated with a dot. + * @param The type of the configuration. + * @param confName The fully qualified name of the configuration in the + * registry. For normal configuration this is the fully + * qualified name of the configuration class. For + * application instance configurations this is the fully + * qualified name of the configuration class joined with + * the primary URL of the application instance, separated + * with a dot. * @param confClass The configuration class. * * @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 findConfiguration(final String confName, final Class confClass) { final Domain registry = domainRepository - .findByDomainKey(REGISTRY_DOMAIN); + .findByDomainKey(REGISTRY_DOMAIN); final Category category = categoryRepository.findByPath(registry, confName); @@ -633,8 +652,8 @@ public class ConfigurationManager { conf = confClass.newInstance(); } catch (InstantiationException | IllegalAccessException ex) { LOGGER.warn(String.format( - "Failed to instantiate configuration \"%s\".", - confClass.getName()), + "Failed to instantiate configuration \"%s\".", + confClass.getName()), ex); return null; } @@ -655,15 +674,15 @@ public class ConfigurationManager { if (setting != null) { try { LOGGER.debug(String. - format("Setting \"%s\" found. Value: %s", - settingPath, - setting.getValue().toString())); + format("Setting \"%s\" found. Value: %s", + settingPath, + setting.getValue().toString())); field.set(conf, setting.getValue()); } catch (IllegalAccessException ex) { LOGGER.warn(String.format( - "Failed to set value of configuration class \"%s\". " + "Failed to set value of configuration class \"%s\". " + "Ignoring.", - confClass.getName()), + confClass.getName()), ex); } } @@ -672,13 +691,103 @@ public class ConfigurationManager { return conf; } + private Category findCategoryForNewSetting(final Object configuration) { + LOGGER.debug(new FormattedMessage( + "#findCategoryForNewSetting: Looking for category for " + + "configuration \"%s\"...", + configuration.getClass().getName())); + final String categoryPath = configuration.getClass().getName(); + final String[] tokens = categoryPath.split("\\."); + final Domain registry = domainRepository + .findByDomainKey(REGISTRY_DOMAIN); + + final Category[] categories = new Category[tokens.length]; + + //Check which of the categories in the categoryPath exist already + final boolean[] exists = new boolean[tokens.length]; + for (int i = 0; i < tokens.length; i++) { + final String path = buildCategoryPath(tokens, i); + LOGGER.debug(new FormattedMessage( + "#findCategoryForNewSetting: Checking if category \"%s\" exists.", + path)); + final Category category = categoryRepository.findByPath(registry, + path); + if (category == null) { + LOGGER.debug(new FormattedMessage( + "#findCategoryForNewSetting: Category \"%s\" does not exist.", + path)); + exists[i] = false; + } else { + LOGGER.debug(new FormattedMessage( + "#findCategoryForNewSetting: Category \"%s\" exists.", + path)); + exists[i] = true; + categories[i] = category; + } + } + + LOGGER.debug( + "#findCategoryForNewSetting: Creating missing categories..."); + for (int i = 0; i < tokens.length; i++) { + LOGGER.debug(new FormattedMessage( + "#findCategoryForNewSetting: Checking for category \"%s\"...", + tokens[i])); + if (!exists[i]) { + + if (i == 0) { + LOGGER.debug(new FormattedMessage( + "#findCategoryForNewSetting: Category \"%s\" does not exist, " + + "creating as subcategory of the registry root category.", + tokens[i])); + categories[i] = createNewCategory(tokens[i], + registry.getRoot()); + } else { + LOGGER.debug(new FormattedMessage( + "#findCategoryForNewSetting: Category \"%s\" does not exist, " + + "creating as subcategory of \"%s\"", + tokens[i], + categories[i - 1].getName())); + categories[i] = createNewCategory(tokens[i], + categories[i - 1]); + } + } + } + + LOGGER.debug(new FormattedMessage( + "#findCategoryForNewSetting: Found/Created category \"%s\".", + categoryPath)); + return categories[categories.length - 1]; + } + + private String buildCategoryPath(final String[] tokens, + final int index) { + final StringJoiner joiner = new StringJoiner("."); + for (int i = 0; i <= index; i++) { + joiner.add(tokens[i]); + } + + return joiner.toString(); + } + + private Category createNewCategory(final String name, + final Category parent) { + final Category category = new Category(); + category.setName(name); + category.setDisplayName(name); + categoryRepository.save(category); + entityManager.flush(); + categoryManager.addSubCategoryToCategory(category, parent); + + return category; + } + private Category createCategoryIfNotExists(final String categoryPath) { LOGGER.debug(String.format("Checking if category \"%s\" exists. If not " - + "the category will be created.", + + "the category will be created.", categoryPath)); final Domain registry = domainRepository. - findByDomainKey(REGISTRY_DOMAIN); + findByDomainKey(REGISTRY_DOMAIN); final Category root = registry.getRoot(); final String[] tokens = categoryPath.split("\\."); @@ -686,14 +795,16 @@ public class ConfigurationManager { categoryPath); if (category == null) { LOGGER.debug(String.format( - "Category \"%s\" was not found. Creating category.", - categoryPath)); + "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); + categoryRepository.save(category); + entityManager.flush(); if (tokens.length > 1) { final StringBuilder parentPath = new StringBuilder(); for (int i = 0; i < tokens.length - 1; i++) { @@ -703,26 +814,26 @@ public class ConfigurationManager { parentPath.append(tokens); } final Category parent = categoryRepository.findByPath( - registry, - parentPath.toString()); + 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)); + "Parent category \"%s\" 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())); + "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)); + "Created category \"%s\" as child of the registry root " + + "category.", + categoryPath)); } } diff --git a/ccm-core/src/main/resources/db/migrations/org/libreccm/ccm_core/h2/V7_0_0_0__create_tables.sql b/ccm-core/src/main/resources/db/migrations/org/libreccm/ccm_core/h2/V7_0_0_0__create_tables.sql index 6c38ef1a8..ede6c4e31 100644 --- a/ccm-core/src/main/resources/db/migrations/org/libreccm/ccm_core/h2/V7_0_0_0__create_tables.sql +++ b/ccm-core/src/main/resources/db/migrations/org/libreccm/ccm_core/h2/V7_0_0_0__create_tables.sql @@ -21,7 +21,7 @@ CATEGORY_ORDER bigint, ENABLED boolean, NAME varchar(255) not null, - UNIQUE_ID varchar(255) not null, + UNIQUE_ID varchar(255), VISIBLE boolean, OBJECT_ID bigint not null, PARENT_CATEGORY_ID bigint, diff --git a/ccm-core/src/main/resources/db/migrations/org/libreccm/ccm_core/pgsql/V7_0_0_0__create_tables.sql b/ccm-core/src/main/resources/db/migrations/org/libreccm/ccm_core/pgsql/V7_0_0_0__create_tables.sql index 6fa300f29..3220547bc 100644 --- a/ccm-core/src/main/resources/db/migrations/org/libreccm/ccm_core/pgsql/V7_0_0_0__create_tables.sql +++ b/ccm-core/src/main/resources/db/migrations/org/libreccm/ccm_core/pgsql/V7_0_0_0__create_tables.sql @@ -21,7 +21,7 @@ CATEGORY_ORDER int8, ENABLED boolean, NAME varchar(255) not null, - UNIQUE_ID varchar(255) not null, + UNIQUE_ID varchar(255), VISIBLE boolean, OBJECT_ID int8 not null, PARENT_CATEGORY_ID int8, diff --git a/ccm-core/src/test/java/org/libreccm/categorization/CategoryManagerTest.java b/ccm-core/src/test/java/org/libreccm/categorization/CategoryManagerTest.java index 88b5627b9..ed23ca54c 100644 --- a/ccm-core/src/test/java/org/libreccm/categorization/CategoryManagerTest.java +++ b/ccm-core/src/test/java/org/libreccm/categorization/CategoryManagerTest.java @@ -224,9 +224,10 @@ public class CategoryManagerTest { @Test @UsingDataSet( "datasets/org/libreccm/categorization/CategoryManagerTest/data.yml") - @ShouldMatchDataSet(value - = "datasets/org/libreccm/categorization/CategoryManagerTest/after-remove-subcategory.yml", - excludeColumns = {"categorization_id", "object_id"}) + @ShouldMatchDataSet( + value = "datasets/org/libreccm/categorization/" + + "CategoryManagerTest/after-remove-subcategory.yml", + excludeColumns = {"categorization_id", "object_id"}) @InSequence(2200) public void removeSubCategoryToCategory() { final Category foo = categoryRepo.findById(-2100L); @@ -235,4 +236,48 @@ public class CategoryManagerTest { categoryManager.removeSubCategoryFromCategory(bar, foo); } + @Test + @UsingDataSet( + "datasets/org/libreccm/categorization/CategoryManagerTest/data.yml") + @ShouldMatchDataSet( + value = "datasets/org/libreccm/categorization/" + + "CategoryManagerTest/after-create-multiple-categories.yml" +// excludeColumns = {"categorization_id", +// "object_id", +// "parent_category_id"} + ) + @InSequence(3100) + public void createMultipleCategories() { + final Domain domain = domainRepo.findByDomainKey("test"); + final Category root = domain.getRoot(); + + final Category com = new Category(); + com.setName("com"); + com.setDisplayName("com"); + com.setUniqueId("com"); + categoryRepo.save(com); + categoryManager.addSubCategoryToCategory(com, root); + + final Category example = new Category(); + example.setName("example"); + example.setDisplayName("example"); + example.setUniqueId("example"); + categoryRepo.save(example); + categoryManager.addSubCategoryToCategory(example, com); + + final Category categories = new Category(); + categories.setName("categories"); + categories.setDisplayName("categories"); + categories.setUniqueId("categories"); + categoryRepo.save(categories); + categoryManager.addSubCategoryToCategory(categories, example); + + final Category test = new Category(); + test.setName("test"); + test.setDisplayName("test"); + test.setUniqueId("test"); + categoryRepo.save(test); + categoryManager.addSubCategoryToCategory(test, categories); + } + } diff --git a/ccm-core/src/test/java/org/libreccm/categorization/CategoryRepositoryTest.java b/ccm-core/src/test/java/org/libreccm/categorization/CategoryRepositoryTest.java index d24111932..25551841a 100644 --- a/ccm-core/src/test/java/org/libreccm/categorization/CategoryRepositoryTest.java +++ b/ccm-core/src/test/java/org/libreccm/categorization/CategoryRepositoryTest.java @@ -175,6 +175,17 @@ public class CategoryRepositoryTest { assertThat(notFound, is(nullValue())); } + @Test + @UsingDataSet( + "datasets/org/libreccm/categorization/CategoryRepositoryTest/data.yml") + @InSequence(1150) + public void findByPathStringNotExisting() { + final Category doesNotExist = categoryRepo.findByPath( + "test:/does/not/exist"); + + assertThat(doesNotExist, is(nullValue())); + } + @Test(expected = InvalidCategoryPathException.class) @UsingDataSet( "datasets/org/libreccm/categorization/CategoryRepositoryTest/data.yml") @@ -214,6 +225,19 @@ public class CategoryRepositoryTest { assertThat(notFound, is(nullValue())); } + @Test + @UsingDataSet( + "datasets/org/libreccm/categorization/CategoryRepositoryTest/data.yml") + @InSequence(1150) + public void findByPathDomainStringNotExisting() { + final Domain domain = domainRepo.findByDomainKey("test"); + + final Category doesNotExist = categoryRepo.findByPath(domain, + "/does/not/exist"); + + assertThat(doesNotExist, is(nullValue())); + } + @Test @UsingDataSet( "datasets/org/libreccm/categorization/CategoryRepositoryTest/data.yml") @@ -227,7 +251,7 @@ public class CategoryRepositoryTest { category.setDisplayName("new-category"); category.setName("new-category"); category.setUniqueId("new0001"); - + categoryRepo.save(category); } diff --git a/ccm-core/src/test/java/org/libreccm/categorization/DatasetsTest.java b/ccm-core/src/test/java/org/libreccm/categorization/DatasetsTest.java index 1448a4602..8a69a580c 100644 --- a/ccm-core/src/test/java/org/libreccm/categorization/DatasetsTest.java +++ b/ccm-core/src/test/java/org/libreccm/categorization/DatasetsTest.java @@ -42,6 +42,7 @@ public class DatasetsTest extends DatasetsVerifier { return Arrays.asList(new String[]{ "/datasets/org/libreccm/categorization/CategoryManagerTest/after-add-obj-to-category.yml", "/datasets/org/libreccm/categorization/CategoryManagerTest/after-add-subcategory.yml", + "/datasets/org/libreccm/categorization/CategoryManagerTest/after-create-multiple-categories.yml", "/datasets/org/libreccm/categorization/CategoryManagerTest/after-remove-obj-from-category.yml", "/datasets/org/libreccm/categorization/CategoryManagerTest/after-remove-subcategory.yml", "/datasets/org/libreccm/categorization/CategoryManagerTest/data.yml", diff --git a/ccm-core/src/test/resources-wildfly8-remote-h2-mem/scripts/create_ccm_core_schema.sql b/ccm-core/src/test/resources-wildfly8-remote-h2-mem/scripts/create_ccm_core_schema.sql index 323821ea8..9d90744fc 100644 --- a/ccm-core/src/test/resources-wildfly8-remote-h2-mem/scripts/create_ccm_core_schema.sql +++ b/ccm-core/src/test/resources-wildfly8-remote-h2-mem/scripts/create_ccm_core_schema.sql @@ -27,7 +27,7 @@ CREATE SCHEMA ccm_core; CATEGORY_ORDER bigint, ENABLED boolean, NAME varchar(255) not null, - UNIQUE_ID varchar(255) not null, + UNIQUE_ID varchar(255), VISIBLE boolean, OBJECT_ID bigint not null, PARENT_CATEGORY_ID bigint, diff --git a/ccm-core/src/test/resources-wildfly8-remote-pgsql/scripts/create_ccm_core_schema.sql b/ccm-core/src/test/resources-wildfly8-remote-pgsql/scripts/create_ccm_core_schema.sql index cb2a83440..3174a72b6 100644 --- a/ccm-core/src/test/resources-wildfly8-remote-pgsql/scripts/create_ccm_core_schema.sql +++ b/ccm-core/src/test/resources-wildfly8-remote-pgsql/scripts/create_ccm_core_schema.sql @@ -27,7 +27,7 @@ CREATE SCHEMA ccm_core; CATEGORY_ORDER int8, ENABLED boolean, NAME varchar(255) not null, - UNIQUE_ID varchar(255) not null, + UNIQUE_ID varchar(255), VISIBLE boolean, OBJECT_ID int8 not null, PARENT_CATEGORY_ID int8, diff --git a/ccm-core/src/test/resources/datasets/org/libreccm/categorization/CategoryManagerTest/after-create-multiple-categories.yml b/ccm-core/src/test/resources/datasets/org/libreccm/categorization/CategoryManagerTest/after-create-multiple-categories.yml new file mode 100644 index 000000000..2cb591c62 --- /dev/null +++ b/ccm-core/src/test/resources/datasets/org/libreccm/categorization/CategoryManagerTest/after-create-multiple-categories.yml @@ -0,0 +1,101 @@ +ccm_core.ccm_objects: + - object_id: -1000 + display_name: test + - object_id: -2000 + display_name: test_root + - object_id: -2100 + display_name: foo + - object_id: -2200 + display_name: bar + - object_id: -3100 + display_name: object1 + - object_id: -3200 + display_name: object2 + - object_id: -3300 + display_name: object3 + - object_id: 1 + display_name: com + - object_id: 2 + display_name: example + - object_id: 3 + display_name: categories + - object_id: 4 + display_name: test + +ccm_core.categories: + - object_id: -2000 + unique_id: test0001 + name: test-root + enabled: true + visible: true + abstract_category: false + category_order: 0 + - object_id: -2100 + unique_id: test0002 + name: foo + parent_category_id: -2000 + enabled: true + visible: true + abstract_category: false + category_order: 0 + - object_id: -2200 + unique_id: test0003 + name: bar + parent_category_id: -2100 + enabled: true + visible: true + abstract_category: false + category_order: 0 + - object_id: 1 + unique_id: com + name: com + parent_category_id: -2000 + enabled: true + visible: true + abstract_category: false + category_order: 1 + - object_id: 2 + unique_id: example + name: example + parent_category_id: 1 + enabled: true + visible: true + abstract_category: false + category_order: 1 + - object_id: 3 + unique_id: categories + name: categories + parent_category_id: 2 + enabled: true + visible: true + abstract_category: false + category_order: 1 + - object_id: 4 + unique_id: test + name: test + parent_category_id: 3 + enabled: true + visible: true + abstract_category: false + category_order: 1 + +ccm_core.category_domains: + - object_id: -1000 + domain_key: test + root_category_id: -2000 + uri: http://libreccm.org/test + version: 1.0 + +ccm_core.categorizations: + - categorization_id: -10000 + category_id: -2100 + object_id: -3100 + object_order: 1 + category_order: 1 + category_index: false + - categorization_id: -10100 + category_id: -2200 + object_id: -3300 + category_order: 1 + object_order: 1 + category_index: false \ No newline at end of file diff --git a/ccm-core/src/test/resources/datasets/org/libreccm/configuration/ConfigurationManagerTest/after-save-new.yml b/ccm-core/src/test/resources/datasets/org/libreccm/configuration/ConfigurationManagerTest/after-save-new.yml index b16c65fea..44f3ba5d1 100644 --- a/ccm-core/src/test/resources/datasets/org/libreccm/configuration/ConfigurationManagerTest/after-save-new.yml +++ b/ccm-core/src/test/resources/datasets/org/libreccm/configuration/ConfigurationManagerTest/after-save-new.yml @@ -21,15 +21,15 @@ ccm_core.ccm_objects: display_name: itemsPerPage - object_id: -3500 display_name: helpUri - - object_id: -2500 + - object_id: 1 display_name: com - - object_id: -2600 + - object_id: 2 display_name: example - - object_id: -2700 + - object_id: 3 display_name: TestConfiguration - - object_id: -3600 + - object_id: 5 display_name: enabled - - object_id: -3700 + - object_id: 7 display_name: itemsPerPage ccm_core.categories: @@ -72,29 +72,26 @@ ccm_core.categories: abstract_category: false parent_category_id: -2300 category_order: 1 - - object_id: -2500 - unique_id: 36223799-5df7-4875-8191-f1ced0965237 + - object_id: 1 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 + - object_id: 2 name: example enabled: true visible: true abstract_category: false - parent_category_id: -2500 + parent_category_id: 1 category_order: 1 - - object_id: -2700 - unique_id: af6c0e93-d60b-4c5f-8fe4-5f82a7f8f923 + - object_id: 3 name: TestConfiguration enabled: true visible: true abstract_category: false - parent_category_id: -2600 + parent_category_id: 2 category_order: 1 ccm_core.category_domains: @@ -104,23 +101,11 @@ ccm_core.category_domains: version: 1.0 ccm_core.categorizations: - - categorization_id: -10100 + - categorization_id: -10500 category_id: -2400 - object_id: -3100 + object_id: -3500 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 + object_order: 5 category_index: false - categorization_id: -10400 category_id: -2400 @@ -128,27 +113,51 @@ ccm_core.categorizations: category_order: 1 object_order: 4 category_index: false - - categorization_id: -10500 + - categorization_id: -10300 category_id: -2400 - object_id: -3500 + object_id: -3300 category_order: 1 - object_order: 5 + object_order: 3 + category_index: false + - categorization_id: -10200 + category_id: -2400 + object_id: -3200 + category_order: 1 + object_order: 2 + category_index: false + - categorization_id: -10100 + category_id: -2400 + object_id: -3100 + category_order: 1 + object_order: 1 + category_index: false + - categorization_id: 4 + category_id: 3 + object_id: 5 + category_order: 1 + object_order: 1 + category_index: false + - categorization_id: 6 + category_id: 3 + object_id: 7 + category_order: 1 + object_order: 2 category_index: false ccm_core.settings: - - object_id: -3100 - name: price - - object_id: -3200 - name: enabled + - object_id: -3500 + name: helpUrl - object_id: -3300 name: minTemperature - object_id: -3400 name: itemsPerPage - - object_id: -3500 - name: helpUrl - - object_id: -3600 + - object_id: -3200 name: enabled - - object_id: -3700 + - object_id: -3100 + name: price + - object_id: 5 + name: enabled + - object_id: 7 name: itemsPerPage ccm_core.settings_big_decimal: @@ -158,7 +167,7 @@ ccm_core.settings_big_decimal: ccm_core.settings_boolean: - object_id: -3200 setting_value: true - - object_id: -3600 + - object_id: 5 setting_value: false ccm_core.settings_double: @@ -168,7 +177,7 @@ ccm_core.settings_double: ccm_core.settings_long: - object_id: -3400 setting_value: 20 - - object_id: -3700 + - object_id: 7 setting_value: 40 ccm_core.settings_string: diff --git a/ccm-core/src/test/resources/scripts/pgsql-cleanup.sql b/ccm-core/src/test/resources/scripts/pgsql-cleanup.sql index ae96b9b81..167412443 100644 --- a/ccm-core/src/test/resources/scripts/pgsql-cleanup.sql +++ b/ccm-core/src/test/resources/scripts/pgsql-cleanup.sql @@ -1,43 +1,43 @@ -DELETE FROM ccm_core.settings_big_decimal; - -DELETE FROM ccm_core.settings_boolean; - -DELETE FROM ccm_core.settings_double; - -DELETE FROM ccm_core.settings_enum_values; - -DELETE FROM ccm_core.settings_enum; - -DELETE FROM ccm_core.settings_l10n_string; - -DELETE FROM ccm_core.settings_l10n_str_values; - -DELETE FROM ccm_core.settings_long; - -DELETE FROM ccm_core.settings_string; - -DELETE FROM ccm_core.settings; - -DELETE FROM ccm_core.categorizations; - -DELETE FROM ccm_core.category_domains; - -DELETE FROM ccm_core.categories; - -DELETE FROM ccm_core.permissions; - -DELETE FROM ccm_core.ccm_objects; - -DELETE FROM ccm_core.role_memberships; - -DELETE FROM ccm_core.group_memberships; - -DELETE FROM ccm_core.groups; - -DELETE FROM ccm_core.users; - -DELETE FROM ccm_core.user_email_addresses; - -DELETE FROM ccm_core.parties; - -DELETE FROM ccm_core.ccm_roles; \ No newline at end of file +-- DELETE FROM ccm_core.settings_big_decimal; +-- +-- DELETE FROM ccm_core.settings_boolean; +-- +-- DELETE FROM ccm_core.settings_double; +-- +-- DELETE FROM ccm_core.settings_enum_values; +-- +-- DELETE FROM ccm_core.settings_enum; +-- +-- DELETE FROM ccm_core.settings_l10n_string; +-- +-- DELETE FROM ccm_core.settings_l10n_str_values; +-- +-- DELETE FROM ccm_core.settings_long; +-- +-- DELETE FROM ccm_core.settings_string; +-- +-- DELETE FROM ccm_core.settings; +-- +-- DELETE FROM ccm_core.categorizations; +-- +-- DELETE FROM ccm_core.category_domains; +-- +-- DELETE FROM ccm_core.categories; +-- +-- DELETE FROM ccm_core.permissions; +-- +-- DELETE FROM ccm_core.ccm_objects; +-- +-- DELETE FROM ccm_core.role_memberships; +-- +-- DELETE FROM ccm_core.group_memberships; +-- +-- DELETE FROM ccm_core.groups; +-- +-- DELETE FROM ccm_core.users; +-- +-- DELETE FROM ccm_core.user_email_addresses; +-- +-- DELETE FROM ccm_core.parties; +-- +-- DELETE FROM ccm_core.ccm_roles; \ No newline at end of file