CCM NG: First part of UI for editing configuration

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4045 8810af33-2d31-482b-a856-94f89814c4df
pull/2/head
jensp 2016-05-02 15:17:14 +00:00
parent aed90bb782
commit f4c09e5739
16 changed files with 861 additions and 138 deletions

View File

@ -129,7 +129,7 @@ public class AdminServlet
new CategoriesTab());
tabbedPane.addTab(
new Label(new GlobalizedMessage("ui.admin.tab.registry.title",
new Label(new GlobalizedMessage("ui.admin.tab.configuration.title",
BUNDLE_NAME)),
new RegistryAdminTab());

View File

@ -0,0 +1,127 @@
/*
* Copyright (C) 2016 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.ui.admin.configuration;
import com.arsdigita.bebop.ActionLink;
import com.arsdigita.bebop.BoxPanel;
import com.arsdigita.bebop.Form;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.ParameterSingleSelectionModel;
import com.arsdigita.bebop.SegmentedPanel;
import com.arsdigita.bebop.form.Submit;
import com.arsdigita.bebop.form.TextField;
import com.arsdigita.bebop.parameters.StringParameter;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.toolbox.ui.LayoutPanel;
import static com.arsdigita.ui.admin.AdminUiConstants.*;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class ConfigurationTab extends LayoutPanel {
private static final String CONF_CLASSES_FILTER = "confClassesFilter";
private final StringParameter selectedConfParam;
private final ParameterSingleSelectionModel<String> selectedConf;
private final StringParameter selectedSettingParam;
private final ParameterSingleSelectionModel<String> selectedSetting;
private final Label confClassesFilterHeading;
private final Form confClassesFilterForm;
private final ConfigurationsTable configurationsTable;
public ConfigurationTab() {
super();
setClassAttr("sidebarNavPanel");
selectedConfParam = new StringParameter("selectedConfiguration");
selectedConf = new ParameterSingleSelectionModel<>(selectedConfParam);
selectedSettingParam = new StringParameter("selectedSetting");
selectedSetting = new ParameterSingleSelectionModel<>(
selectedSettingParam);
final SegmentedPanel left = new SegmentedPanel();
confClassesFilterHeading = new Label(new GlobalizedMessage(
"ui.admin.configuration.classes.filter.heading", ADMIN_BUNDLE));
confClassesFilterForm = new Form("confClassesForm");
final TextField confClassesFilter = new TextField(CONF_CLASSES_FILTER);
confClassesFilterForm.add(confClassesFilter);
confClassesFilterForm.add(new Submit(new GlobalizedMessage(
"ui.admin.configuration.classes.filter.submit", ADMIN_BUNDLE)));
final ActionLink clearLink = new ActionLink(new GlobalizedMessage(
"ui.admin.configuration.classes.filter.clear", ADMIN_BUNDLE));
clearLink.addActionListener(e -> {
final PageState state = e.getPageState();
confClassesFilter.setValue(state, null);
});
confClassesFilterForm.add(clearLink);
left.addSegment(confClassesFilterHeading, confClassesFilterForm);
setLeft(left);
final BoxPanel body = new BoxPanel(BoxPanel.VERTICAL);
configurationsTable = new ConfigurationsTable(
this, selectedConf, confClassesFilter);
body.add(configurationsTable);
setBody(body);
}
@Override
public void register(final Page page) {
super.register(page);
page.setVisibleDefault(confClassesFilterHeading, true);
page.setVisibleDefault(confClassesFilterForm, true);
page.setVisibleDefault(configurationsTable, true);
}
protected void showConfigurationsTable(final PageState state) {
confClassesFilterHeading.setVisible(state, true);
confClassesFilterForm.setVisible(state, true);
configurationsTable.setVisible(state, true);
}
protected void hideConfigurationsTable(final PageState state) {
confClassesFilterHeading.setVisible(state, false);
confClassesFilterForm.setVisible(state, false);
configurationsTable.setVisible(state, false);
}
protected void showConfiguration(final PageState state) {
hideConfigurationsTable(state);
}
protected void hideConfiguration(final PageState state) {
showConfigurationsTable(state);
}
}

View File

@ -0,0 +1,241 @@
/*
* Copyright (C) 2016 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.ui.admin.configuration;
import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.ControlLink;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.ParameterSingleSelectionModel;
import com.arsdigita.bebop.Table;
import com.arsdigita.bebop.event.TableActionEvent;
import com.arsdigita.bebop.event.TableActionListener;
import com.arsdigita.bebop.table.TableCellRenderer;
import com.arsdigita.bebop.table.TableColumn;
import com.arsdigita.bebop.table.TableColumnModel;
import com.arsdigita.bebop.table.TableModel;
import com.arsdigita.bebop.table.TableModelBuilder;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.util.LockableImpl;
import com.arsdigita.util.UncheckedWrapperException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.configuration.SettingInfo;
import org.libreccm.configuration.SettingManager;
import org.libreccm.l10n.GlobalizationHelper;
import java.util.List;
import java.util.logging.Level;
import static com.arsdigita.ui.admin.AdminUiConstants.*;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class ConfigurationTable extends Table {
private static final Logger LOGGER = LogManager.getLogger(
ConfigurationTable.class);
private static final int COL_SETTING_LABEL = 0;
private static final int COL_SETTING_VALUE = 1;
private static final int COL_SETTING_DESC = 2;
private static final int COL_EDIT_SETTING = 3;
private ParameterSingleSelectionModel<String> selectedConf;
public ConfigurationTable(
final ConfigurationTab configurationTab,
final ParameterSingleSelectionModel<String> selectedConf,
final ParameterSingleSelectionModel<String> selectedSetting) {
super();
setIdAttr("configurationTable");
this.selectedConf = selectedConf;
setEmptyView(new Label(new GlobalizedMessage(
"ui.admin.configuration.settings.none", ADMIN_BUNDLE)));
final TableColumnModel columnModel = getColumnModel();
columnModel.add(new TableColumn(
COL_SETTING_LABEL,
new Label(new GlobalizedMessage(
"ui.admin.configuration.settings.table.col_setting_label.header",
ADMIN_BUNDLE))));
columnModel.add(new TableColumn(
COL_SETTING_VALUE,
new Label(new GlobalizedMessage(
"ui.admin.configuration.settings.table.col_setting_value.header",
ADMIN_BUNDLE))));
columnModel.add(new TableColumn(
COL_SETTING_DESC,
new Label(new GlobalizedMessage(
"ui.admin.configuration.settings.table.col_setting_desc.header",
ADMIN_BUNDLE))));
columnModel.add(new TableColumn(
COL_EDIT_SETTING,
new Label(new GlobalizedMessage(
"ui.admin.configuration.settings.table.col_edit_setting.header",
ADMIN_BUNDLE))));
columnModel.get(COL_EDIT_SETTING).setCellRenderer(
new TableCellRenderer() {
@Override
public Component getComponent(final Table table,
final PageState state,
final Object value,
final boolean isSelected,
final Object key,
final int row,
final int column) {
return new ControlLink((String) value);
}
});
addTableActionListener(new TableActionListener() {
@Override
public void cellSelected(final TableActionEvent event) {
final PageState state = event.getPageState();
if (event.getColumn() == COL_EDIT_SETTING) {
final String settingName = (String) event.getRowKey();
selectedSetting.setSelectedKey(state, settingName);
}
}
@Override
public void headSelected(final TableActionEvent event) {
//Nothing
}
});
setModelBuilder(new ConfigurationTableModelBuilder());
}
private class ConfigurationTableModelBuilder
extends LockableImpl implements TableModelBuilder {
@Override
public TableModel makeModel(final Table table, final PageState state) {
final ConfigurationManager confManager = CdiUtil.createCdiUtil()
.findBean(ConfigurationManager.class);
final Class<?> confClass;
try {
confClass = Class.forName(selectedConf.getSelectedKey(state));
} catch (ClassNotFoundException ex) {
LOGGER.error("Configuration class '{}' not found.",
selectedConf.getSelectedKey(state));
throw new UncheckedWrapperException(String.format(
"Configuration class '%s not found'",
selectedConf.getSelectedKey(state)), ex);
}
final Object configuration = confManager
.findConfiguration(confClass);
return new ConfigurationTableModel(configuration, state);
}
}
private class ConfigurationTableModel implements TableModel {
private final Object configuration;
private final ConfigurationManager confManager;
private final SettingManager settingManager;
private final GlobalizationHelper globalizationHelper;
private final List<String> settings;
private int index = -1;
public ConfigurationTableModel(final Object configuration,
final PageState state) {
this.configuration = configuration;
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
confManager = cdiUtil.findBean(ConfigurationManager.class);
settingManager = cdiUtil.findBean(SettingManager.class);
globalizationHelper = cdiUtil.findBean(GlobalizationHelper.class);
settings = settingManager.getAllSettings(configuration.getClass());
}
@Override
public int getColumnCount() {
return 4;
}
@Override
public boolean nextRow() {
index++;
return index < settings.size();
}
@Override
public Object getElementAt(final int columnIndex) {
final String setting = settings.get(index);
final SettingInfo settingInfo = settingManager.getSettingInfo(
configuration.getClass(), setting);
switch (columnIndex) {
case COL_SETTING_LABEL:
return settingInfo.getLabel(globalizationHelper
.getNegotiatedLocale());
case COL_SETTING_VALUE: {
try {
return configuration.getClass().getField(setting).get(
configuration);
} catch (NoSuchFieldException | SecurityException | IllegalAccessException ex) {
LOGGER.error("Failed to read value from configuration.",
ex);
return new Label(new GlobalizedMessage(
"ui.admin.configuration.settings.read_error",
ADMIN_BUNDLE));
}
}
case COL_SETTING_DESC:
return settingInfo.getDescription(globalizationHelper
.getNegotiatedLocale());
case COL_EDIT_SETTING:
return new Label(new GlobalizedMessage(
"ui.admin.configuration.settings.edit", ADMIN_BUNDLE));
default:
throw new IllegalArgumentException("Illegal column index");
}
}
@Override
public Object getKeyAt(final int columnIndex) {
return settings.get(index);
}
}
}

View File

@ -0,0 +1,217 @@
/*
* Copyright (C) 2016 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.ui.admin.configuration;
import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.ControlLink;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.ParameterSingleSelectionModel;
import com.arsdigita.bebop.Table;
import com.arsdigita.bebop.event.TableActionEvent;
import com.arsdigita.bebop.event.TableActionListener;
import com.arsdigita.bebop.form.TextField;
import com.arsdigita.bebop.table.TableCellRenderer;
import com.arsdigita.bebop.table.TableColumn;
import com.arsdigita.bebop.table.TableColumnModel;
import com.arsdigita.bebop.table.TableModel;
import com.arsdigita.bebop.table.TableModelBuilder;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.util.LockableImpl;
import org.apache.logging.log4j.util.Strings;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.configuration.ConfigurationInfo;
import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.l10n.GlobalizationHelper;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.SortedSet;
import java.util.stream.Collectors;
import static com.arsdigita.ui.admin.AdminUiConstants.*;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class ConfigurationsTable extends Table {
private static final int COL_TITLE = 0;
private static final int COL_DESC = 1;
public ConfigurationsTable(
final ConfigurationTab configurationTab,
final ParameterSingleSelectionModel<String> selectedConf,
final TextField confClassesFilter) {
super();
setIdAttr("configurationsTable");
setEmptyView(new Label(new GlobalizedMessage(
"ui.admin.configuration.configurations.none", ADMIN_BUNDLE)));
final TableColumnModel columnModel = getColumnModel();
columnModel.add(new TableColumn(
COL_TITLE,
new Label(new GlobalizedMessage(
"ui.admin.configuration.configurations.table.name",
ADMIN_BUNDLE))));
columnModel.add(new TableColumn(
COL_DESC,
new Label(new GlobalizedMessage(
"ui.admin.configuration.configurations.table.desc",
ADMIN_BUNDLE))));
columnModel.get(COL_TITLE).setCellRenderer(new TableCellRenderer() {
@Override
public Component getComponent(final Table table,
final PageState state,
final Object value,
final boolean isSelected,
final Object key,
final int row,
final int column) {
return new ControlLink((String) value);
}
});
addTableActionListener(new TableActionListener() {
@Override
public void cellSelected(final TableActionEvent event) {
final PageState state = event.getPageState();
if (event.getColumn() == COL_TITLE) {
final String confClassName = (String) event.getRowKey();
selectedConf.setSelectedKey(state, confClassName);
}
}
@Override
public void headSelected(final TableActionEvent event) {
//Nothing
}
});
setModelBuilder(new ConfigurationsTableModelBuilder(confClassesFilter));
}
private class ConfigurationsTableModelBuilder
extends LockableImpl implements TableModelBuilder {
private final TextField confClassesFilter;
public ConfigurationsTableModelBuilder(
final TextField confClassesField) {
this.confClassesFilter = confClassesField;
}
@Override
public TableModel makeModel(final Table table,
final PageState state) {
table.getRowSelectionModel().clearSelection(state);
return new ConfigurationsTableModel(confClassesFilter, state);
}
}
private class ConfigurationsTableModel implements TableModel {
private final List<Class<?>> configurations;
private int index = -1;
private final ConfigurationManager confManager;
private final Locale negoiatedLocale;
public ConfigurationsTableModel(final TextField confClassesFilter,
final PageState state) {
final String filterTerm = (String) confClassesFilter
.getValue(state);
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
confManager = cdiUtil.findBean(ConfigurationManager.class);
final GlobalizationHelper globalizationHelper = cdiUtil.findBean(
GlobalizationHelper.class);
negoiatedLocale = globalizationHelper.getNegotiatedLocale();
final SortedSet<Class<?>> confs = confManager
.findAllConfigurations();
configurations = confs.stream()
.filter(c -> {
final ConfigurationInfo info = confManager
.getConfigurationInfo(c);
// return c.getName().startsWith(filterTerm);
return info.getTitle(negoiatedLocale).startsWith(filterTerm);
})
.collect(Collectors.toCollection(ArrayList::new));
configurations.sort((c1, c2) -> {
// return c1.getName().compareTo(c2.getName());
final ConfigurationInfo info1 = confManager
.getConfigurationInfo(c1);
final ConfigurationInfo info2 = confManager
.getConfigurationInfo(c2);
return info1.getTitle(negoiatedLocale)
.compareTo(info2.getTitle(negoiatedLocale));
});
}
@Override
public int getColumnCount() {
return 2;
}
@Override
public boolean nextRow() {
index++;
return index < configurations.size();
}
@Override
public Object getElementAt(final int columnIndex) {
final ConfigurationInfo info = confManager.getConfigurationInfo(
configurations.get(index));
switch (columnIndex) {
case COL_TITLE:
if (Strings.isBlank(info.getTitle(negoiatedLocale))) {
return configurations.get(index).getSimpleName();
} else {
return info.getTitle(negoiatedLocale);
}
case COL_DESC:
return info.getDescription(negoiatedLocale);
default:
throw new IllegalArgumentException("Illegal column index");
}
}
@Override
public Object getKeyAt(final int columnIndex) {
return configurations.get(index).getName();
}
}
}

View File

@ -18,7 +18,6 @@
*/
package org.libreccm.configuration;
import org.libreccm.configuration.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@ -26,37 +25,44 @@ import java.lang.annotation.Target;
import java.util.ResourceBundle;
/**
* Marks a class as configuration class which is managed by the
* Marks a class as configuration class which is managed by the
* {@link ConfigurationManager}.
*
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Configuration {
/**
* The name of the configuration. If left blank the simple name of the class
* is used.
*
*
* @return Name of the configuration.
*/
//String name() default "";
/**
* Points to the {@link ResourceBundle} containing the descriptions
* of the configuration and all entries of the configuration.
*
* Points to the {@link ResourceBundle} containing the descriptions of the
* configuration and all entries of the configuration.
*
* @return Fully qualified name of the {@link ResourceBundle}.
*/
String descBundle() default "";
/**
* Key of the description of the configuration in the resource bundle
* provided by {@link #descBundle()}.
* Key of the title of the description in the resource bundle provided by
* {@link #descBundle()}.
*
* @return Key of the title
*/
String titleKey() default "";
/**
* Key of the description of the configuration in the resource bundle
* provided by {@link #descBundle()}.
*
* @return Key of the description.
*/
String descKey() default "";
}

View File

@ -26,8 +26,7 @@ import java.util.ResourceBundle;
import java.util.TreeMap;
/**
* Describes a configuration. Useful for generating user
* interfaces.
* Describes a configuration. Useful for generating user interfaces.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@ -44,6 +43,8 @@ public final class ConfigurationInfo {
*/
private String descBundle;
private String titleKey;
/**
* The key for the description of the configuration in the resource bundle.
*/
@ -79,6 +80,14 @@ public final class ConfigurationInfo {
return ResourceBundle.getBundle(descBundle);
}
public String getTitleKey() {
return titleKey;
}
void setTitleKey(final String titleKey) {
this.titleKey = titleKey;
}
public String getDescKey() {
return descKey;
}
@ -87,6 +96,10 @@ public final class ConfigurationInfo {
this.descKey = descKey;
}
public String getTitle(final Locale locale) {
return getDescriptionBundle(locale).getString(titleKey);
}
public String getDescription(final Locale locale) {
return getDescriptionBundle(locale).getString(descKey);
}

View File

@ -19,12 +19,21 @@
package org.libreccm.configuration;
import java.lang.reflect.Field;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.util.Strings;
import org.libreccm.modules.CcmModule;
import org.libreccm.modules.Module;
import java.util.Arrays;
import java.util.ServiceLoader;
import java.util.SortedSet;
import java.util.TreeSet;
/**
* Maps between configuration classes and the settings stored in the database.
@ -43,9 +52,37 @@ public class ConfigurationManager {
@Inject
private SettingConverter settingConverter;
@Inject
private EntityManager entityManager;
/**
* Finds all configuration classes listed by the installed modules.
*
* @return A sorted set containing all configuration classes.
*
* @see Module#configurations()
*/
public SortedSet<Class<?>> findAllConfigurations() {
final ServiceLoader<CcmModule> modules = ServiceLoader.load(
CcmModule.class);
final SortedSet<Class<?>> configurations = new TreeSet<>((c1, c2) -> {
return c1.getName().compareTo(c2.getName());
});
for(CcmModule module : modules) {
final Module annotation = module.getClass().getAnnotation(
Module.class);
if (annotation == null) {
continue;
}
Arrays.stream(annotation.configurations()).forEach(c -> {
configurations.add(c);
});
}
return configurations;
}
/**
* Load all settings of the provided configuration class.
*
@ -170,8 +207,12 @@ public class ConfigurationManager {
} else {
confInfo.setDescBundle(annotation.descBundle());
}
if (annotation.descKey() == null
|| annotation.descKey().isEmpty()) {
if (Strings.isBlank(annotation.titleKey())) {
confInfo.setTitleKey("title");
} else {
confInfo.setTitleKey(annotation.titleKey());
}
if (Strings.isBlank(annotation.descKey())) {
confInfo.setDescKey("description");
} else {
confInfo.setDescKey(annotation.descKey());

View File

@ -114,6 +114,10 @@ public final class SettingInfo {
void setLabelKey(final String labelKey) {
this.labelKey = labelKey;
}
public String getLabel(final Locale locale) {
return getDescriptionBundle(locale).getString(labelKey);
}
public String getDescKey() {
return descKey;

View File

@ -20,13 +20,18 @@ package org.libreccm.configuration;
import java.lang.reflect.Field;
import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.transaction.Transactional;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.util.Strings;
import java.util.ArrayList;
/**
*
@ -43,18 +48,55 @@ import org.apache.logging.log4j.Logger;
public class SettingManager {
private static final Logger LOGGER = LogManager.getLogger(
SettingManager.class);
SettingManager.class);
@Inject
private EntityManager entityManager;
/**
* Get the names of all settings of a configuration class.
*
* @param configuration The configuration class for which the settings are
* retrieved.
*
* @return A list with the names of all settings provided by the
* configuration class.
*/
public List<String> getAllSettings(final Class<?> configuration) {
if (configuration == null) {
throw new IllegalArgumentException("Configuration can't be null");
}
if (configuration.getAnnotation(Configuration.class) == null) {
throw new IllegalArgumentException(String.format(
"The class \"%s\" of the provided object is not annotated "
+ "with \"%s\".",
configuration.getClass().getName(),
Configuration.class.getName()));
}
final List<String> settings = new ArrayList<>();
final Field[] fields = configuration.getDeclaredFields();
for (Field field : fields) {
if (field.getAnnotation(Setting.class) != null) {
settings.add(field.getName());
}
}
settings.sort((s1, s2) -> {
return s1.compareTo(s2);
});
return settings;
}
/**
* 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.
*/
@ -62,18 +104,18 @@ public class SettingManager {
"PMD.CyclomaticComplexity",
"PMD.StandardCyclomaticComplexity"})
public SettingInfo getSettingInfo(
final Class<?> configuration,
final String name) {
final Class<?> configuration,
final String name) {
if (configuration == null) {
throw new IllegalArgumentException("Configuration can't be null");
}
if (configuration.getAnnotation(Configuration.class) == null) {
throw new IllegalArgumentException(String.format(
"The class \"%s\" of the provided object is not annotated "
+ "with \"%s\".",
configuration.getClass().getName(),
Configuration.class.getName()));
"The class \"%s\" of the provided object is not annotated "
+ "with \"%s\".",
configuration.getClass().getName(),
Configuration.class.getName()));
}
final Field field;
@ -81,10 +123,10 @@ public class SettingManager {
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;
}
@ -96,7 +138,7 @@ public class SettingManager {
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());
@ -109,7 +151,7 @@ public class SettingManager {
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);
}
@ -117,16 +159,14 @@ public class SettingManager {
settingInfo.setConfClass(configuration.getName());
settingInfo.setDescBundle(getDescBundle(configuration));
if (settingAnnotation.labelKey() == null
|| settingAnnotation.labelKey().isEmpty()) {
if (Strings.isBlank(settingAnnotation.labelKey())) {
settingInfo.setLabelKey(String.join(".", field.getName(),
"label"));
} else {
settingInfo.setLabelKey(name);
}
if (settingAnnotation.descKey() == null
|| settingAnnotation.descKey().isEmpty()) {
if (Strings.isBlank(settingAnnotation.descKey())) {
settingInfo.setDescKey(String.join(".",
field.getName(),
"descripotion"));
@ -140,25 +180,25 @@ public class SettingManager {
/**
* 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 confName Name of the configuration to which the setting belongs
* @param name The fully qualified name of the setting.
* @param clazz The class 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 <T> AbstractSetting<T> findSetting(final String confName,
final String name,
final Class<T> 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 TypedQuery<AbstractSetting> query = entityManager.
createNamedQuery("AbstractSetting.findByClassAndName",
AbstractSetting.class);
createNamedQuery("AbstractSetting.findByClassAndName",
AbstractSetting.class);
query.setParameter("class", confName);
query.setParameter("name", name);
final List<AbstractSetting> result = query.getResultList();
@ -185,9 +225,9 @@ public class SettingManager {
private String getDescBundle(final Class<?> configuration) {
final Configuration confAnnotation = configuration.getAnnotation(
Configuration.class);
Configuration.class);
if (confAnnotation.descBundle() == null
|| confAnnotation.descBundle().isEmpty()) {
|| confAnnotation.descBundle().isEmpty()) {
return String.join("",
configuration.getClass().getName(),
"Description");
@ -195,4 +235,5 @@ public class SettingManager {
return confAnnotation.descBundle();
}
}
}

View File

@ -18,12 +18,18 @@
*/
package org.libreccm.core;
import com.arsdigita.bebop.BebopConfig;
import com.arsdigita.kernel.KernelConfig;
import com.arsdigita.mail.MailConfig;
import com.arsdigita.notification.NotificationConfig;
import com.arsdigita.ui.admin.AdminApplicationCreator;
import com.arsdigita.ui.admin.AdminServlet;
import com.arsdigita.ui.admin.AdminApplicationSetup;
import com.arsdigita.ui.login.LoginApplicationCreator;
import com.arsdigita.ui.login.LoginServlet;
import com.arsdigita.ui.login.LoginApplicationSetup;
import com.arsdigita.workflow.simple.WorkflowConfig;
import com.arsdigita.xml.XmlConfig;
import org.libreccm.modules.CcmModule;
import org.libreccm.modules.InitEvent;
@ -31,9 +37,10 @@ import org.libreccm.modules.InstallEvent;
import org.libreccm.modules.Module;
import org.libreccm.modules.ShutdownEvent;
import org.libreccm.modules.UnInstallEvent;
import org.libreccm.security.EmailTemplates;
import org.libreccm.security.OneTimeAuthConfig;
import org.libreccm.security.SystemUsersSetup;
import org.libreccm.web.ApplicationType;
/**
@ -51,48 +58,23 @@ import org.libreccm.web.ApplicationType;
singleton = true,
creator = AdminApplicationCreator.class,
servlet = AdminServlet.class)},
entities = {org.libreccm.auditing.CcmRevision.class,
org.libreccm.categorization.Categorization.class,
org.libreccm.categorization.Category.class,
org.libreccm.categorization.Domain.class,
org.libreccm.categorization.DomainOwnership.class,
org.libreccm.core.CcmObject.class,
org.libreccm.core.Resource.class,
org.libreccm.core.ResourceType.class,
org.libreccm.modules.InstalledModule.class,
org.libreccm.formbuilder.Component.class,
org.libreccm.formbuilder.DataDrivenSelect.class,
org.libreccm.formbuilder.FormSection.class,
org.libreccm.formbuilder.Listener.class,
org.libreccm.formbuilder.MetaObject.class,
org.libreccm.formbuilder.ObjectType.class,
org.libreccm.formbuilder.Option.class,
org.libreccm.formbuilder.PersistentDataQuery.class,
org.libreccm.formbuilder.ProcessListener.class,
org.libreccm.formbuilder.Widget.class,
org.libreccm.formbuilder.WidgetLabel.class,
org.libreccm.formbuilder.actions.ConfirmEmailListener.class,
org.libreccm.formbuilder.actions.ConfirmRedirectListener.class,
org.libreccm.formbuilder.actions.RemoteServerPostListener.class,
org.libreccm.formbuilder.actions.SimpleEmailListener.class,
org.libreccm.formbuilder.actions.TemplateEmailListener.class,
org.libreccm.formbuilder.actions.XmlEmailListener.class,
org.libreccm.messaging.Attachment.class,
org.libreccm.messaging.Message.class,
org.libreccm.messaging.MessageThread.class,
org.libreccm.notification.Digest.class,
org.libreccm.notification.Notification.class,
org.libreccm.notification.QueueItem.class,
org.libreccm.portal.Portal.class,
org.libreccm.portal.Portlet.class,
org.libreccm.runtime.Initalizer.class,
org.libreccm.search.lucene.Document.class,
org.libreccm.search.lucene.Index.class,
org.libreccm.web.CcmApplication.class,
org.libreccm.web.Host.class,
org.libreccm.workflow.Task.class,
org.libreccm.workflow.UserTask.class,
org.libreccm.workflow.Workflow.class})
configurations = {
com.arsdigita.bebop.BebopConfig.class,
com.arsdigita.dispatcher.DispatcherConfig.class,
com.arsdigita.globalization.GlobalizationConfig.class,
com.arsdigita.kernel.KernelConfig.class,
com.arsdigita.kernel.security.SecurityConfig.class,
com.arsdigita.mail.MailConfig.class,
com.arsdigita.notification.NotificationConfig.class,
com.arsdigita.templating.TemplatingConfig.class,
com.arsdigita.ui.UIConfig.class,
com.arsdigita.web.WebConfig.class,
com.arsdigita.workflow.simple.WorkflowConfig.class,
com.arsdigita.xml.XmlConfig.class,
com.arsdigita.xml.formatters.DateFormatterConfig.class,
org.libreccm.security.EmailTemplates.class,
org.libreccm.security.OneTimeAuthConfig.class,
})
public class CcmCore implements CcmModule {
@Override
@ -100,13 +82,15 @@ public class CcmCore implements CcmModule {
// final EntityManager entityManager = event.getEntityManager();
final SystemUsersSetup systemUsersSetup = new SystemUsersSetup(
event);
event);
systemUsersSetup.setupSystemUsers();
final AdminApplicationSetup adminSetup = new AdminApplicationSetup(event);
final AdminApplicationSetup adminSetup
= new AdminApplicationSetup(event);
adminSetup.setup();
final LoginApplicationSetup loginSetup = new LoginApplicationSetup(event);
final LoginApplicationSetup loginSetup
= new LoginApplicationSetup(event);
loginSetup.setup();
}

View File

@ -18,6 +18,8 @@
*/
package org.libreccm.modules;
import org.libreccm.configuration.Configuration;
import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.web.ApplicationType;
import java.lang.annotation.Retention;
@ -29,59 +31,63 @@ import java.lang.annotation.Target;
/**
* Annotation for describing some meta data of a module.
*
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Target({TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Module {
/**
* Name of the module, overriding the name provided by the pom.xml and the
* module info file of the module.
*
* @return The name of the module, overriding the value provided by the
* module-info file.
/**
* Name of the module, overriding the name provided by the pom.xml and the
* module info file of the module.
*
* @return The name of the module, overriding the value provided by the
* module-info file.
*/
String name() default "";
/**
* Package name of resources of the package like DB migrations, overriding
* default value constructed from the group id and the artifact id of the
/**
* Package name of resources of the package like DB migrations, overriding
* default value constructed from the group id and the artifact id of the
* module.
*
* @return The package name for resources of the module.
*
* @return The package name for resources of the module.
*/
String packageName() default "";
/**
* The version of module, overriding the value provided by the module info
/**
* The version of module, overriding the value provided by the module info
* file of the module.
*
* @return The version of the module.
*
* @return The version of the module.
*/
String version() default "";
/**
* Modules required by the annotated module.
*
*
* @return An array of the dependencies of the module.
*/
RequiredModule[] requiredModules() default {};
/**
* ApplicationType types provided by the annotated module.
*
* @return An array containing the type descriptions for all application
* types provided by the annotated module.
*
* @return An array containing the type descriptions for all application
* types provided by the annotated module.
*/
ApplicationType[] applicationTypes() default {};
/**
* The JPA entities provided by the annotated module.
* Configuration classes provided by the module.
*
* @return An array containing all configuration classes provided by the
* module.
*
* @return An array with the JPA entity classes of the annotated module.
* @see Configuration
* @see ConfigurationManager
*/
Class<?>[] entities() default {};
Class<?>[] configurations() default {};
}

View File

@ -59,10 +59,6 @@ public class ModuleInfo {
* The data package of the module (group id).
*/
private String moduleDataPackage;
/**
* The entities provided by the module.
*/
private Class<?>[] moduleEntities;
/**
* The version of the module.
*/
@ -129,10 +125,6 @@ public class ModuleInfo {
return moduleVersion;
}
public List<Class<?>> getModuleEntities() {
return Collections.unmodifiableList(Arrays.asList(moduleEntities));
}
public List<RequiredModule> getRequiredModules() {
return Collections.unmodifiableList(Arrays.asList(requiredModules));
}
@ -168,7 +160,6 @@ public class ModuleInfo {
LOGGER.info("Module version is \"{}.\"", moduleVersion);
requiredModules = annotation.requiredModules();
moduleEntities = annotation.entities();
}
/**

View File

@ -154,7 +154,7 @@ ui.admin.user.userpasswordform.retrieving_user_failed=Failed to retrieve user
ui.admin.groups.couldnt_find_specified_group=Couldn't find the specified group
ui.admin.tab.users_groups_roles.title=Users/Groups/Roles
ui.admin.tab.categories.title=Categories
ui.admin.tab.registry.title=Registry
ui.admin.tab.configuration.title=Configuration
ui.admin.change_password=Change password
ui.admin.tab.workflows.title=Workflows
ui.admin.users_groups_roles.users.title=Users
@ -408,3 +408,16 @@ ui.admin.categories.doamin_details.mappings.error.please_select_app=Please selec
ui.admin.categories.domain_details.mappings.remove.confirm=Are you sure to remove this domain mapping?
ui.admin.categories.tree.header=Categories
ui.admin.categories.tree.back=Back to domain properties
ui.admin.configuration.classes.filter.heading=Filter configurations
ui.admin.configuration.classes.filter.submit=Apply
ui.admin.configuration.classes.filter.clear=Clear
ui.admin.configuration.configurations.none=No matching configurations found.
ui.admin.configuration.configurations.table.name=Name
ui.admin.configuration.configurations.table.desc=Description
ui.admin.configuration.settings.none=No settings
ui.admin.configuration.settings.table.col_setting_label.header=Setting
ui.admin.configuration.settings.table.col_setting_value.header=Value
ui.admin.configuration.settings.table.col_setting_desc.header=Description
ui.admin.configuration.settings.table.col_edit_setting.header=Edit
ui.admin.configuration.settings.edit=Edit
ui.admin.configuration.settings.read_error=Failed to read setting value.

View File

@ -154,7 +154,7 @@ ui.admin.user.userpasswordform.retrieving_user_failed=Konnte Benutzer nicht abru
ui.admin.groups.couldnt_find_specified_group=Konnte die spezifische Gruppe nicht finden
ui.admin.tab.users_groups_roles.title=Benutzer/Gruppen/Rollen
ui.admin.tab.categories.title=Kategorien
ui.admin.tab.registry.title=Registry
ui.admin.tab.configuration.title=Konfiguration
ui.admin.change_password=Passwort \u00e4ndern
ui.admin.tab.workflows.title=Arbeitsabl\u00e4ufe
ui.admin.users_groups_roles.users.title=Benutzer
@ -411,3 +411,16 @@ ui.admin.categories.doamin_details.mappings.error.please_select_app=Bitte w\u00e
ui.admin.categories.domain_details.mappings.remove.confirm=Sind Sie sicher, dass Sie dieses Mapping entfernen wollen?
ui.admin.categories.tree.header=Kategorien
ui.admin.categories.tree.back=Zur\u00fcck zur Domain Eigenschaften
ui.admin.configuration.classes.filter.heading=Konfigurationen filtern
ui.admin.configuration.classes.filter.submit=Anwenden
ui.admin.configuration.classes.filter.clear=Zur\u00fccksetzen
ui.admin.configuration.configurations.none=Keine passenden Konfigurationen gefunden.
ui.admin.configuration.configurations.table.name=Name
ui.admin.configuration.configurations.table.desc=Beschreibung
ui.admin.configuration.settings.none=Keine Parameter
ui.admin.configuration.settings.table.col_setting_label.header=Parameter
ui.admin.configuration.settings.table.col_setting_value.header=Wert
ui.admin.configuration.settings.table.col_setting_desc.header=Beschreibung
ui.admin.configuration.settings.table.col_edit_setting.header=Bearbeiten
ui.admin.configuration.settings.edit=Bearbeiten
ui.admin.configuration.settings.read_error=Fehler beim lesen des Parameters.

View File

@ -112,7 +112,7 @@ ui.admin.user.userpasswordform.retrieving_user_failed=Failed to retrieve user
ui.admin.groups.couldnt_find_specified_group=Couldn't find the specified group
ui.admin.tab.users_groups_roles.title=Users/Groups/Roles
ui.admin.tab.categories.title=Categories
ui.admin.tab.registry.title=Registry
ui.admin.tab.configuration.title=Configuration
ui.admin.change_password=Change password
ui.admin.tab.workflows.title=Workflows
ui.admin.tab.sysinfo.title=System information
@ -384,3 +384,16 @@ ui.admin.categories.doamin_details.mappings.error.please_select_app=Please selec
ui.admin.categories.domain_details.mappings.remove.confirm=Are you sure to remove this domain mapping?
ui.admin.categories.tree.header=Categories
ui.admin.categories.tree.back=Back to domain properties
ui.admin.configuration.classes.filter.heading=Filter configurations
ui.admin.configuration.classes.filter.submit=Apply
ui.admin.configuration.classes.filter.clear=Clear
ui.admin.configuration.configurations.none=No matching configurations found.
ui.admin.configuration.configurations.table.name=Name
ui.admin.configuration.configurations.table.desc=Description
ui.admin.configuration.settings.none=No settings
ui.admin.configuration.settings.table.col_setting_label.header=Setting
ui.admin.configuration.settings.table.col_setting_value.header=Value
ui.admin.configuration.settings.table.col_setting_desc.header=Description
ui.admin.configuration.settings.table.col_edit_setting.header=Edit
ui.admin.configuration.settings.edit=Edit
ui.admin.configuration.settings.read_error=Failed to read setting value.

View File

@ -97,7 +97,7 @@ ui.admin.user.userpasswordform.retrieving_user_failed=Impossible de retrouver l'
ui.admin.groups.couldnt_find_specified_group=Impossible de trouver le groupe sp\u00e9cifi\u00e9
ui.admin.tab.users_groups_roles.title=
ui.admin.tab.categories.title=Categories
ui.admin.tab.registry.title=Registry
ui.admin.tab.configuration.title=Configuration
ui.admin.change_password=Change password
ui.admin.tab.workflows.title=Workflows
ui.admin.save=Save
@ -375,3 +375,16 @@ ui.admin.categories.doamin_details.mappings.error.please_select_app=Please selec
ui.admin.categories.domain_details.mappings.remove.confirm=Are you sure to remove this domain mapping?
ui.admin.categories.tree.header=Categories
ui.admin.categories.tree.back=Back to domain properties
ui.admin.configuration.classes.filter.heading=Filter configurations
ui.admin.configuration.classes.filter.submit=Apply
ui.admin.configuration.classes.filter.clear=Clear
ui.admin.configuration.configurations.none=No matching configurations found.
ui.admin.configuration.configurations.table.name=Name
ui.admin.configuration.configurations.table.desc=Description
ui.admin.configuration.settings.none=No settings
ui.admin.configuration.settings.table.col_setting_label.header=Setting
ui.admin.configuration.settings.table.col_setting_value.header=Value
ui.admin.configuration.settings.table.col_setting_desc.header=Description
ui.admin.configuration.settings.table.col_edit_setting.header=Edit
ui.admin.configuration.settings.edit=Edit
ui.admin.configuration.settings.read_error=Failed to read setting value.