CCM NG: Database based configuration now passes all test cases. Not all planned features are yet implemented and tested (for example application instance specific configurations). They will be implemented and tested when they are needed.

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@3776 8810af33-2d31-482b-a856-94f89814c4df
pull/2/head
jensp 2015-12-18 15:35:48 +00:00
parent 4b5a227772
commit dabb99d46f
13 changed files with 561 additions and 261 deletions

View File

@ -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));
}

View File

@ -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<Long, Category>
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<Category> 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();

View File

@ -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.
*
@ -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) {
@ -287,8 +296,8 @@ public class ConfigurationManager {
*
* @param configuration The configuration class to which the settings
* belongs.
* @param name The name of the setting for which the {@link SettingInfo} is
* generated.
* @param name The name of the setting for which the
* {@link SettingInfo} is generated.
*
* @return The {@link SettingInfo} for the provided configuration class.
*/
@ -496,13 +505,13 @@ public class ConfigurationManager {
return (AbstractSetting<T>) new EnumSetting();
} else if (LocalizedString.class.getName().equals(valueTypeName)) {
return (AbstractSetting<T>) new LocalizedStringSetting();
} else if (LongSetting.class.getName().equals(valueTypeName)) {
} else if (Long.class.getName().equals(valueTypeName)) {
return (AbstractSetting<T>) new LongSetting();
} else if (String.class.getName().equals(valueTypeName)) {
return (AbstractSetting<T>) new StringSetting();
} else {
throw new IllegalArgumentException(String.format(
"No setting type for value type \"s\".", valueTypeName));
"No setting type for value type \"%s\".", valueTypeName));
}
}
@ -523,7 +532,10 @@ public class ConfigurationManager {
"%s.%s",
configuration.getClass().getName(),
settingName);
LOGGER.debug(String.format("Saving setting \"%s\"...", settingPath));
LOGGER.debug(new FormattedMessage(
"Saving setting \"%s\" of type \"%s\"...",
settingPath,
valueType.getName()));
AbstractSetting<T> setting = findSetting(settingPath, valueType);
if (setting == null) {
LOGGER.debug(String.format("Setting \"%s\" does not yet exist in "
@ -531,24 +543,28 @@ public class ConfigurationManager {
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,6 +579,7 @@ public class ConfigurationManager {
LOGGER.debug("Saving changed setting to DB...");
entityManager.merge(setting);
entityManager.flush();
}
/**
@ -608,10 +625,12 @@ public class ConfigurationManager {
*
* @param <T> 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.
* 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
@ -672,6 +691,96 @@ 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.",
@ -694,6 +803,8 @@ public class ConfigurationManager {
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++) {
@ -707,8 +818,8 @@ public class ConfigurationManager {
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.",
"Parent category \"%s\" for new category \"%s\" "
+ "does not exist, but should. Can't continue.",
parentPath.toString(),
categoryPath));
}

View File

@ -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,

View File

@ -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,

View File

@ -224,8 +224,9 @@ public class CategoryManagerTest {
@Test
@UsingDataSet(
"datasets/org/libreccm/categorization/CategoryManagerTest/data.yml")
@ShouldMatchDataSet(value
= "datasets/org/libreccm/categorization/CategoryManagerTest/after-remove-subcategory.yml",
@ShouldMatchDataSet(
value = "datasets/org/libreccm/categorization/"
+ "CategoryManagerTest/after-remove-subcategory.yml",
excludeColumns = {"categorization_id", "object_id"})
@InSequence(2200)
public void removeSubCategoryToCategory() {
@ -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);
}
}

View File

@ -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")

View File

@ -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",

View File

@ -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,

View File

@ -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,

View File

@ -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

View File

@ -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:

View File

@ -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;
-- 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;