diff --git a/ccm-core/src/main/java/com/arsdigita/bebop/PropertySheet.java b/ccm-core/src/main/java/com/arsdigita/bebop/PropertySheet.java
new file mode 100644
index 000000000..314a8a14e
--- /dev/null
+++ b/ccm-core/src/main/java/com/arsdigita/bebop/PropertySheet.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.bebop;
+
+import com.arsdigita.bebop.table.TableCellRenderer;
+import com.arsdigita.bebop.table.TableModel;
+import com.arsdigita.bebop.table.TableModelBuilder;
+import com.arsdigita.bebop.util.GlobalizationUtil;
+import com.arsdigita.globalization.GlobalizedMessage;
+import com.arsdigita.util.LockableImpl;
+
+
+/**
+ * Displays a list of label-value pairs that
+ * represent the properties of some object. For example, a
+ * typical PropertySheet may look like this:
+ *
+ *
+ * | First Name: | Stanislav |
+ * | Last Name: | Freidin |
+ * | Mission: | Sleep |
+ *
+ *
+ * This class relies on the {@link PropertySheetModelBuilder} to
+ * supply it with the right {@link PropertySheetModel} during
+ * each request. It is up to the user to provide the right
+ * builder.
+ *
+ *
+ * @author Stanislav Freidin
+ * @version $Id: PropertySheet.java 287 2005-02-22 00:29:02Z sskracic $
+ *
+ */
+public class PropertySheet extends Table {
+
+
+ private PropertySheetModelBuilder m_builder;
+
+ /**
+ * Constructs a new PropertySheet.
+ *
+ * @param modelBuilder the property sheet model builder
+ * that is responsible for building the property
+ * sheet model
+ *
+ */
+ public PropertySheet(PropertySheetModelBuilder modelBuilder) {
+ super(new PSTMBAdapter(modelBuilder), new Object[]{"Label", "Value"});
+ super.setHeader(null);
+
+ super.getColumn(0).setCellRenderer(new GlobalizedLabelCellRenderer(Label.BOLD));
+ super.getColumn(1).setCellRenderer(new StringLabelCellRenderer(null));
+ }
+
+ /**
+ * Constructs a new PropertySheet and sets the output
+ * escape value.
+ *
+ * @param modelBuilder the property sheet model builder
+ * that is responsible for building the property
+ * sheet model
+ * @param valueOutputEscape the value of the label-value
+ * pair's output-escaping
+ *
+ */
+ public PropertySheet(PropertySheetModelBuilder modelBuilder, boolean valueOutputEscape) {
+ super(new PSTMBAdapter(modelBuilder), new Object[]{"Label", "Value"});
+ super.setHeader(null);
+
+ super.getColumn(0).setCellRenderer(new GlobalizedLabelCellRenderer(Label.BOLD));
+ super.getColumn(1).setCellRenderer(new StringLabelCellRenderer(valueOutputEscape));
+ }
+
+ /**
+ * Returns the {@link PropertySheetModelBuilder}.
+ * @return the {@link PropertySheetModelBuilder}.
+ */
+ public PropertySheetModelBuilder getPropertySheetModelBuilder() {
+ return m_builder;
+ }
+
+ // Convert a PropertySheetModelBuilder to a TableModelBuilder
+ private static class PSTMBAdapter
+ extends LockableImpl implements TableModelBuilder {
+
+ private PropertySheetModelBuilder m_builder;
+
+ public PSTMBAdapter(PropertySheetModelBuilder b) {
+ m_builder = b;
+ }
+
+ public TableModel makeModel(Table t, PageState s) {
+ return new TableModelAdapter(
+ m_builder.makeModel((PropertySheet)t, s)
+ );
+ }
+
+ public void lock() {
+ m_builder.lock();
+ super.lock();
+ }
+ }
+
+ // Wraps a PropertySheetModel
+ private static class TableModelAdapter implements TableModel {
+
+ private PropertySheetModel m_model;
+ private int m_row;
+
+ public TableModelAdapter(PropertySheetModel model) {
+ m_model = model;
+ m_row = -1;
+ }
+
+ public int getColumnCount() { return 2; }
+
+ public boolean nextRow() {
+ m_row++;
+ return m_model.nextRow();
+ }
+
+ public Object getElementAt(int columnIndex) {
+ if(columnIndex == 0) {
+ return m_model.getGlobalizedLabel();
+ } else {
+ return m_model.getValue();
+ }
+ }
+
+ public Object getKeyAt(int columnIndex) {
+ return new Integer(m_row);
+ }
+
+ public PropertySheetModel getPSModel() {
+ return m_model;
+ }
+ };
+
+ // Renders strings as labels
+ public static class StringLabelCellRenderer implements TableCellRenderer {
+
+ private String m_weight;
+ private boolean m_outputEscape = false;
+
+ public StringLabelCellRenderer(String weight) {
+ m_weight = weight;
+ }
+
+ public StringLabelCellRenderer(boolean outputEscape) {
+ m_outputEscape = outputEscape;
+ }
+
+ public Component getComponent(Table table, PageState state, Object value,
+ boolean isSelected, Object key,
+ int row, int column) {
+ Label t = getLabel(value);
+ //t.setOutputEscaping(false);
+ t.setOutputEscaping(m_outputEscape);
+ if(m_weight != null) {
+ t.setFontWeight(m_weight);
+ }
+ return t;
+ }
+
+ protected Label getLabel(Object value) {
+ return new Label((String)value);
+ }
+ }
+
+ // Renders strings as labels
+ public static class GlobalizedLabelCellRenderer extends StringLabelCellRenderer {
+
+ public GlobalizedLabelCellRenderer(String weight) {
+ super(weight);
+ }
+
+ public GlobalizedLabelCellRenderer(boolean outputEscape) {
+ super(outputEscape);
+ }
+
+ protected Label getLabel(Object value) {
+ return new Label((GlobalizedMessage)value);
+ }
+ }
+
+ /**
+ * An empty {@link PropertySheetModel}.
+ */
+ public static final PropertySheetModel EMPTY_MODEL =
+ new PropertySheetModel() {
+ public boolean nextRow() { return false; }
+ public String getLabel() {
+ throw new IllegalStateException("The model is empty");
+ }
+ public GlobalizedMessage getGlobalizedLabel() {
+ throw new IllegalStateException((String) GlobalizationUtil.globalize("bebop.the_model_is_empty").localize());
+ }
+ public String getValue() {
+ throw new IllegalStateException("The model is empty");
+ }
+ };
+
+}
diff --git a/ccm-core/src/main/java/com/arsdigita/bebop/PropertySheetModel.java b/ccm-core/src/main/java/com/arsdigita/bebop/PropertySheetModel.java
new file mode 100644
index 000000000..b875534ea
--- /dev/null
+++ b/ccm-core/src/main/java/com/arsdigita/bebop/PropertySheetModel.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.bebop;
+
+import com.arsdigita.globalization.GlobalizedMessage;
+
+/**
+ * An abstraction that the
+ * {@link PropertySheet} class uses to display a
+ * 2-column table of label-value pairs.
+ *
+ * @author Stanislav Freidin
+ * @version $Id: PropertySheetModel.java 287 2005-02-22 00:29:02Z sskracic $
+ * @see PropertySheetModelBuilder
+ */
+
+public interface PropertySheetModel {
+
+
+ /**
+ * Advances to the next property, if possible.
+ *
+ * @return false if there are no more properties;
+ * true otherwise.
+ */
+ boolean nextRow();
+
+ /**
+ * Returns the label for the current property.
+ *
+ * @return the current label.
+ * @deprecated use getGlobalizedLabel() instead
+ */
+ String getLabel();
+
+ /**
+ * Returns the GlobalizedMessage for the current property
+ * @return the current GlobalizedMessage
+ */
+ GlobalizedMessage getGlobalizedLabel();
+
+
+ /**
+ * Returns the string representation of the current property.
+ *
+ * @return the current value formatted as a string.
+ */
+ String getValue();
+
+}
diff --git a/ccm-core/src/main/java/com/arsdigita/bebop/PropertySheetModelBuilder.java b/ccm-core/src/main/java/com/arsdigita/bebop/PropertySheetModelBuilder.java
new file mode 100644
index 000000000..effaabeb4
--- /dev/null
+++ b/ccm-core/src/main/java/com/arsdigita/bebop/PropertySheetModelBuilder.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.bebop;
+
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.util.Lockable;
+
+/**
+ * Constructs a new {@link PropertySheetModel} for the {@link PropertySheet}.
+ * The model will be used to get a list of properties at runtime.
+ *
+ * @author Stanislav Freidin
+ * @version $Id: PropertySheetModelBuilder.java 287 2005-02-22 00:29:02Z sskracic $
+ * @see PropertySheetModel
+ */
+
+public interface PropertySheetModelBuilder extends Lockable {
+
+
+ /**
+ * Constructs a new {@link PropertySheetModel}.
+ *
+ * @param sheet the {@link PropertySheet}
+ * @param state the page state
+ * @return a {@link PropertySheetModel}.
+ */
+ PropertySheetModel makeModel(PropertySheet sheet, PageState state);
+
+}
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/AdminServlet.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/AdminServlet.java
index 60c8162ea..f0aec7898 100644
--- a/ccm-core/src/main/java/com/arsdigita/ui/admin/AdminServlet.java
+++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/AdminServlet.java
@@ -224,13 +224,13 @@ public class AdminServlet extends BaseApplicationServlet implements
/*
* Create application administration panel
*/
- // ToDo tabbedPane.addTab(APPLICATIONS_TAB_TITLE,
- // ToDo new ApplicationsAdministrationTab());
+ tabbedPane.addTab(APPLICATIONS_TAB_TITLE,
+ new ApplicationsAdministrationTab());
// browsePane.setTabbedPane(tabbedPane);
// browsePane.setGroupAdministrationTab(groupAdminTab);
//Add System information tab
- // ToDo tabbedPane.addTab(SYSINFO_TAB_TITLE, new SystemInformationTab());
+ tabbedPane.addTab(SYSINFO_TAB_TITLE, new SystemInformationTab());
page.add(tabbedPane);
page.lock();
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/ApplicationManagers.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/ApplicationManagers.java
new file mode 100644
index 000000000..27bef045c
--- /dev/null
+++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/ApplicationManagers.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2010 Jens Pelzetter, ScientificCMS.org team
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.ui.admin;
+
+import com.arsdigita.ui.admin.applications.ApplicationManager;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Helper class for managing the implementations of the {@link ApplicationManager} interface
+ *
+ * @author Jens Pelzetter
+ * @version $Id: ApplicationManagers.java 2294 2013-08-05 18:39:46Z jensp $
+ */
+public class ApplicationManagers {
+
+ private Map> appManagers = new HashMap>();
+
+ /**
+ * The one and only instance of this class. The pattern used here ensures that
+ * the instance is created at the first access, but not earlier.
+ */
+ private static class Instance {
+ private static final ApplicationManagers INSTANCE = new ApplicationManagers();
+ }
+
+ /**
+ * Private constructor to ensure that no instances of this class can be created.
+ */
+ private ApplicationManagers() {
+ //Nothing
+ }
+
+ /**
+ * @return The instance of this class.
+ */
+ public static ApplicationManagers getInstance() {
+ return Instance.INSTANCE;
+ }
+
+ public static void register(final ApplicationManager> appManager) {
+ getInstance().registerApplicationManager(appManager);
+ }
+
+ public void registerApplicationManager(final ApplicationManager> appManager) {
+ appManagers.put(appManager.getApplication().getName(), appManager);
+ }
+
+ protected Map> getApplicationManagers() {
+ return Collections.unmodifiableMap(appManagers);
+ }
+
+ protected ApplicationManager> getApplicationManager(final String appClassName) {
+ return appManagers.get(appClassName);
+ }
+
+}
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/ApplicationsAdministrationTab.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/ApplicationsAdministrationTab.java
new file mode 100644
index 000000000..5ece31a0d
--- /dev/null
+++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/ApplicationsAdministrationTab.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2013 Jens Pelzetter
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.ui.admin;
+
+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.SimpleContainer;
+import com.arsdigita.bebop.Tree;
+import com.arsdigita.bebop.event.ChangeEvent;
+import com.arsdigita.bebop.event.ChangeListener;
+import com.arsdigita.toolbox.ui.LayoutPanel;
+import com.arsdigita.ui.admin.applications.ApplicationInstanceAwareContainer;
+import com.arsdigita.ui.admin.applications.ApplicationInstancePane;
+import com.arsdigita.ui.admin.applications.ApplicationManager;
+import com.arsdigita.ui.admin.applications.BaseApplicationPane;
+import com.arsdigita.ui.admin.applications.MultiInstanceApplicationPane;
+import com.arsdigita.ui.admin.applications.SingletonApplicationPane;
+import com.arsdigita.ui.admin.applications.tree.ApplicationTreeModelBuilder;
+import com.arsdigita.util.UncheckedWrapperException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import org.libreccm.cdi.utils.CdiLookupException;
+import org.libreccm.cdi.utils.CdiUtil;
+import org.libreccm.web.ApplicationRepository;
+import org.libreccm.web.ApplicationType;
+import org.libreccm.web.CcmApplication;
+
+/**
+ * A tab for managing CcmApplication and application instances.
+ *
+ * @author pb
+ * @author Jens Pelzetter
+ */
+public class ApplicationsAdministrationTab extends LayoutPanel implements
+ AdminConstants {
+
+ private final Tree applicationTree;
+ private final Map appPanes
+ = new HashMap<>();
+ private final Map instancePanes
+ = new HashMap<>();
+ private final BoxPanel appPanel;
+
+ /**
+ * Constructor
+ */
+ public ApplicationsAdministrationTab() {
+
+ super();
+
+ setClassAttr("sidebarNavPanel");
+ setAttribute("navbar-title", "Sitemap");
+
+ applicationTree = new Tree(new ApplicationTreeModelBuilder());
+ applicationTree.addChangeListener(new TreeStateChangeListener());
+
+ setClassAttr("navbar");
+
+ setLeft(applicationTree);
+
+ final CdiUtil cdiUtil = new CdiUtil();
+ final org.libreccm.web.ApplicationManager appManager;
+ try {
+ appManager = cdiUtil.findBean(
+ org.libreccm.web.ApplicationManager.class);
+ } catch (CdiLookupException ex) {
+ throw new UncheckedWrapperException(ex);
+ }
+
+ final Collection applicationTypes = appManager.
+ getApplicationTypes().values();
+
+ final Map> appManagers
+ = ApplicationManagers.
+ getInstance().
+ getApplicationManagers();
+
+ for (ApplicationType appType : applicationTypes) {
+ if (appType.singleton()) {
+ createSingletonAppPane(appType, appManagers);
+ } else {
+ createAppPane(appType, appManagers);
+ }
+ }
+
+ appPanel = new BoxPanel();
+ appPanel.setClassAttr("main");
+ for (Map.Entry entry : appPanes.entrySet()) {
+ appPanel.add(entry.getValue());
+ }
+
+ for (Map.Entry entry : instancePanes.
+ entrySet()) {
+ appPanel.add(entry.getValue());
+ }
+
+ //setRight(appPanel);
+ setBody(appPanel);
+ }
+
+ private void createSingletonAppPane(final ApplicationType applicationType,
+ final Map> appManagers) {
+ final String appObjectType = applicationType.name();
+
+ final ApplicationManager> manager = appManagers.get(appObjectType);
+ final SingletonApplicationPane pane;
+ if (manager == null) {
+ pane = new SingletonApplicationPane(applicationType, null);
+ } else {
+ pane = new SingletonApplicationPane(
+ applicationType, appManagers.get(appObjectType).
+ getApplicationAdminForm());
+ }
+ appPanes.put(appObjectType, pane);
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ private void createAppPane(
+ final ApplicationType applicationType,
+ final Map> appManagers) {
+ final ApplicationManager> appManager = appManagers.get(
+ applicationType.name());
+ final Form createForm;
+ if (appManager == null) {
+ createForm = null;
+ } else {
+ createForm = appManager.getApplicationCreateForm();
+ }
+
+ final MultiInstanceApplicationPane> appPane = new MultiInstanceApplicationPane(
+ applicationType, createForm);
+ appPanes.put(applicationType.name(), appPane);
+ createInstancePane(applicationType, appManagers);
+ }
+
+ private void createInstancePane(
+ final ApplicationType applicationType,
+ final Map> managementForms) {
+ final ApplicationManager> manager = managementForms.get(
+ applicationType.name());
+ final ApplicationInstancePane instPane;
+ if (manager == null) {
+ instPane = new ApplicationInstancePane(new Placeholder());
+ } else {
+ instPane = new ApplicationInstancePane(managementForms.get(
+ applicationType.name()).
+ getApplicationAdminForm());
+ }
+
+ instancePanes.put(applicationType.name(), instPane);
+ }
+
+ @Override
+ public void register(final Page page) {
+ super.register(page);
+
+ for (Map.Entry entry : appPanes.entrySet()) {
+ page.setVisibleDefault(entry.getValue(), false);
+ }
+ for (Map.Entry entry : instancePanes.
+ entrySet()) {
+ page.setVisibleDefault(entry.getValue(), false);
+ }
+ }
+
+ private void setPaneVisible(final SimpleContainer pane,
+ final PageState state) {
+ for (Map.Entry entry : appPanes.entrySet()) {
+ entry.getValue().setVisible(state, false);
+ }
+ for (Map.Entry entry : instancePanes.
+ entrySet()) {
+ entry.getValue().setVisible(state, false);
+ }
+
+ pane.setVisible(state, true);
+ }
+
+ private class TreeStateChangeListener implements ChangeListener {
+
+ public TreeStateChangeListener() {
+ //Nothing
+ }
+
+ @Override
+ public void stateChanged(final ChangeEvent event) {
+ final PageState state = event.getPageState();
+
+ final String selectedKey = (String) applicationTree.getSelectedKey(
+ state);
+ if (selectedKey != null) {
+ if (selectedKey.contains(".")) {
+ // Selected key is a classname and therefore the key of an ApplicationPane
+ final BaseApplicationPane pane = appPanes.get(selectedKey);
+ if (pane != null) {
+ setPaneVisible(pane, state);
+ }
+ } else {
+ // Selected key is the name of a instance pane
+ final CdiUtil cdiUtil = new CdiUtil();
+ final ApplicationRepository appRepo;
+ try {
+ appRepo = cdiUtil.findBean(ApplicationRepository.class);
+ } catch (CdiLookupException ex) {
+ throw new UncheckedWrapperException(ex);
+ }
+
+ final CcmApplication application = appRepo
+ .retrieveApplicationForPath(selectedKey);
+
+ final ApplicationInstancePane pane;
+ if (application != null) {
+ pane = instancePanes.get(application.getClass().
+ getName());
+ if (pane != null) {
+ pane.setApplication(application);
+ }
+ } else {
+ pane = null;
+ }
+
+ if (pane != null) {
+ setPaneVisible(pane, state);
+ }
+ }
+ }
+ }
+
+ }
+
+ private class Placeholder extends ApplicationInstanceAwareContainer {
+
+ public Placeholder() {
+ super();
+ final Label label = new Label(GlobalizationUtil.globalize(
+ "ui.admin.applications.placeholder"));
+ add(label);
+ }
+
+ }
+}
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/SystemInformationTab.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/SystemInformationTab.java
new file mode 100644
index 000000000..9af7b9610
--- /dev/null
+++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/SystemInformationTab.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2013 Jens Pelzetter
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */package com.arsdigita.ui.admin;
+
+import com.arsdigita.bebop.Label;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.PropertySheet;
+import com.arsdigita.bebop.PropertySheetModel;
+import com.arsdigita.bebop.PropertySheetModelBuilder;
+import com.arsdigita.bebop.SegmentedPanel;
+import com.arsdigita.globalization.GlobalizedMessage;
+import com.arsdigita.toolbox.ui.LayoutPanel;
+import com.arsdigita.util.LockableImpl;
+import com.arsdigita.util.SystemInformation;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerFactory;
+import org.xml.sax.SAXException;
+
+/**
+ *
+ * @author Jens Pelzetter
+ * @version $Id: SystemInformationTab.java 2923 2014-10-27 18:55:26Z jensp $
+ */
+public class SystemInformationTab extends LayoutPanel implements AdminConstants {
+
+ public SystemInformationTab() {
+ super();
+
+ final SegmentedPanel panel = new SegmentedPanel();
+
+ panel.addSegment(new Label(GlobalizationUtil.globalize("ui.admin.sysinfo.appinfo")),
+ new PropertySheet(new CCMSysInfoPropertySheetModelBuilder()));
+
+ panel.addSegment(new Label(GlobalizationUtil.globalize(
+ "ui.admin.sysinfo.java_system_properties")),
+ new PropertySheet(new JavaSystemPropertiesSheetModelBuilder()));
+
+ panel.addSegment(new Label(GlobalizationUtil.globalize("ui.admin.sysinfo.xml_config")),
+ new PropertySheet(new XMLConfigSheetModelBuilder()));
+
+ setRight(panel);
+ }
+
+ private class CCMSysInfoPropertySheetModelBuilder
+ extends LockableImpl
+ implements PropertySheetModelBuilder {
+
+ public CCMSysInfoPropertySheetModelBuilder() {
+ super();
+ }
+
+ @Override
+ public PropertySheetModel makeModel(final PropertySheet sheet, final PageState state) {
+ return new CCMSysInfoPropertySheetModel();
+ }
+
+ }
+
+ private class CCMSysInfoPropertySheetModel implements PropertySheetModel {
+
+ private final SystemInformation sysInfo;
+ private final Iterator> sysInfoIterator;
+ private Map.Entry currentProperty;
+
+ public CCMSysInfoPropertySheetModel() {
+ sysInfo = SystemInformation.getInstance();
+ sysInfoIterator = sysInfo.iterator();
+ }
+
+ @Override
+ public boolean nextRow() {
+ final boolean result = sysInfoIterator.hasNext();
+ if (result) {
+ currentProperty = sysInfoIterator.next();
+ }
+ return result;
+
+ }
+
+ @Override
+ public String getLabel() {
+ if (currentProperty == null) {
+ return null;
+ } else {
+ return currentProperty.getKey();
+ }
+ }
+
+ @Override
+ public GlobalizedMessage getGlobalizedLabel() {
+ return GlobalizationUtil.globalize(currentProperty.getKey());
+ }
+
+ @Override
+ public String getValue() {
+ return currentProperty.getValue();
+ }
+
+ }
+
+ private class JavaSystemPropertiesSheetModelBuilder
+ extends LockableImpl
+ implements PropertySheetModelBuilder {
+
+ public JavaSystemPropertiesSheetModelBuilder() {
+ super();
+ }
+
+ @Override
+ public PropertySheetModel makeModel(final PropertySheet sheet, final PageState state) {
+ return new JavaSystemPropertiesSheetModel();
+ }
+
+ }
+
+ private class JavaSystemPropertiesSheetModel implements PropertySheetModel {
+
+ private final Properties systemProperties;
+ private final Enumeration> enumeration;
+ private Object currentElement;
+
+ public JavaSystemPropertiesSheetModel() {
+ systemProperties = System.getProperties();
+ enumeration = systemProperties.propertyNames();
+ }
+
+ @Override
+ public boolean nextRow() {
+ final boolean result = enumeration.hasMoreElements();
+ if (result) {
+ currentElement = enumeration.nextElement();
+ }
+ return result;
+ }
+
+ @Override
+ public String getLabel() {
+ return currentElement.toString();
+ }
+
+ @Override
+ public GlobalizedMessage getGlobalizedLabel() {
+ return GlobalizationUtil.globalize(currentElement.toString());
+ }
+
+ @Override
+ public String getValue() {
+ return systemProperties.getProperty(currentElement.toString());
+ }
+
+ }
+
+ private class XMLConfigSheetModelBuilder
+ extends LockableImpl
+ implements PropertySheetModelBuilder {
+
+ public XMLConfigSheetModelBuilder() {
+ super();
+ }
+
+ @Override
+ public PropertySheetModel makeModel(final PropertySheet sheet, final PageState state) {
+ return new XMLConfigSheetModel();
+ }
+
+ }
+
+ private class XMLConfigSheetModel implements PropertySheetModel {
+
+ private static final int TRANSFORMER_FACTORY_INDEX = 0;
+ private static final int TRANSFORMER_INDEX = 1;
+ private static final int DOCUMENT_BUILDER_FACTORY_INDEX = 2;
+ private static final int DOCUMENT_BUILDER_INDEX = 3;
+ private static final int SAX_PARSER_FACTORY_INDEX = 4;
+ private static final int SAX_PARSER_INDEX = 5;
+ private int currentIndex = -1;
+
+ public XMLConfigSheetModel() {
+ //Nothing
+ }
+
+ @Override
+ public boolean nextRow() {
+ currentIndex++;
+ return currentIndex <= SAX_PARSER_INDEX;
+ }
+
+ @Override
+ public String getLabel() {
+ switch (currentIndex) {
+ case TRANSFORMER_FACTORY_INDEX:
+ return "XML Transformer Factory";
+ case TRANSFORMER_INDEX:
+ return "XML Transformer";
+ case DOCUMENT_BUILDER_FACTORY_INDEX:
+ return "XML Document Builder Factory";
+ case DOCUMENT_BUILDER_INDEX:
+ return "XML Document Builder";
+ case SAX_PARSER_FACTORY_INDEX:
+ return "SAX Parser Factory";
+ case SAX_PARSER_INDEX:
+ return "SAX Parser";
+ default:
+ return "";
+ }
+ }
+
+ @Override
+ public GlobalizedMessage getGlobalizedLabel() {
+ switch (currentIndex) {
+ case TRANSFORMER_FACTORY_INDEX:
+ return GlobalizationUtil.globalize("ui.admin.sysinfo.xml_transformer_factory");
+ case TRANSFORMER_INDEX:
+ return GlobalizationUtil.globalize("ui.admin.sysinfo.xml_transformer");
+ case DOCUMENT_BUILDER_FACTORY_INDEX:
+ return GlobalizationUtil.globalize(
+ "ui.admin.sysinfo.xml_document_builder_factory");
+ case DOCUMENT_BUILDER_INDEX:
+ return GlobalizationUtil.globalize("ui.admin.sysinfo.xml_document_builder");
+ case SAX_PARSER_FACTORY_INDEX:
+ return GlobalizationUtil.globalize("ui.admin.sysinfo.sax_parser_factory");
+ case SAX_PARSER_INDEX:
+ return GlobalizationUtil.globalize("ui.admin.sysinfo.sax_parser");
+ default:
+ return GlobalizationUtil.globalize("unknown");
+ }
+ }
+
+ @Override
+ public String getValue() {
+ switch (currentIndex) {
+ case TRANSFORMER_FACTORY_INDEX:
+ return TransformerFactory.newInstance().getClass().getName();
+ case TRANSFORMER_INDEX:
+ try {
+ return TransformerFactory.newInstance().newTransformer().getClass().getName();
+ } catch(TransformerConfigurationException ex) {
+ return "???";
+ }
+ case DOCUMENT_BUILDER_FACTORY_INDEX:
+ return DocumentBuilderFactory.newInstance().getClass().getName();
+ case DOCUMENT_BUILDER_INDEX:
+ try{
+ return DocumentBuilderFactory.newInstance().newDocumentBuilder().getClass()
+ .getName();
+ } catch(ParserConfigurationException ex) {
+ return "???";
+ }
+ case SAX_PARSER_FACTORY_INDEX:
+ return SAXParserFactory.newInstance().getClass().getName();
+ case SAX_PARSER_INDEX:
+ try {
+ return SAXParserFactory.newInstance().newSAXParser().getClass().getName();
+ } catch(ParserConfigurationException ex) {
+ return "???";
+ } catch(SAXException ex) {
+ return "???";
+ }
+ default:
+ return "";
+ }
+ }
+
+ }
+
+}
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/UserAdministrationTab.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/UserAdministrationTab.java
index 89bd0a122..636420f17 100644
--- a/ccm-core/src/main/java/com/arsdigita/ui/admin/UserAdministrationTab.java
+++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/UserAdministrationTab.java
@@ -64,20 +64,20 @@ class UserAdministrationTab extends LayoutPanel {
setLeft(sections);
final UserBrowsePane browsePane = new UserBrowsePane();
- // ToDo final UserSummarySection summarySection = new UserSummarySection(this, browsePane);
- // ToDo final UserSearchSection searchSection = new UserSearchSection(this, browsePane);
- // ToDo final UserCreateSection createSection = new UserCreateSection(this);
-
- browsePane.setTabbedPane(parent);
- browsePane.setGroupAdministrationTab(groupAdminTab);
-
- final BoxPanel body = new BoxPanel();
- // ToDo addSection(USER_TAB_SUMMARY, summarySection, body);
- addSection(USER_TAB_BROWSE, browsePane, body);
- // ToDo addSection(USER_TAB_SEARCH, searchSection, body);
- // ToDo addSection(USER_TAB_CREATE_USER, createSection, body);
-
- setBody(body);
+// final UserSummarySection summarySection = new UserSummarySection(this, browsePane);
+// final UserSearchSection searchSection = new UserSearchSection(this, browsePane);
+// final UserCreateSection createSection = new UserCreateSection(this);
+//
+// browsePane.setTabbedPane(parent);
+// browsePane.setGroupAdministrationTab(groupAdminTab);
+//
+// final BoxPanel body = new BoxPanel();
+// addSection(USER_TAB_SUMMARY, summarySection, body);
+// addSection(USER_TAB_BROWSE, browsePane, body);
+// addSection(USER_TAB_SEARCH, searchSection, body);
+// addSection(USER_TAB_CREATE_USER, createSection, body);
+//
+// setBody(body);
}
/**
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationInfoPropertySheetModel.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationInfoPropertySheetModel.java
new file mode 100644
index 000000000..edb7e983e
--- /dev/null
+++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationInfoPropertySheetModel.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2013 Jens Pelzetter
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.ui.admin.applications;
+
+import com.arsdigita.bebop.PropertySheetModel;
+import com.arsdigita.ui.admin.GlobalizationUtil;
+import com.arsdigita.globalization.GlobalizedMessage;
+import com.arsdigita.util.UncheckedWrapperException;
+import java.util.List;
+import org.libreccm.cdi.utils.CdiLookupException;
+import org.libreccm.cdi.utils.CdiUtil;
+import org.libreccm.web.ApplicationRepository;
+import org.libreccm.web.ApplicationType;
+import org.libreccm.web.CcmApplication;
+
+/**
+ * A property sheet model for displaying informations about an
+ * {@link ApplicationType} using a {@link PropertySheet}.
+ *
+ * @author Jens Pelzetter
+ * @version $Id: ApplicationInfoPropertySheetModel.java 2220 2013-06-19
+ * 15:26:58Z jensp $
+ */
+public class ApplicationInfoPropertySheetModel implements PropertySheetModel {
+
+ private static final int APP_TITLE = 0;
+ private static final int APP_CLASS = 1;
+ private static final int APP_SINGLETON = 2;
+ private static final int APP_DESC = 3;
+ private static final int SINGLETON_PATH = 4;
+ private final ApplicationType applicationType;
+ private int currentIndex = -1;
+
+ public ApplicationInfoPropertySheetModel(
+ final ApplicationType applicationType) {
+ this.applicationType = applicationType;
+ }
+
+ @Override
+ public boolean nextRow() {
+ if (applicationType.singleton() && currentIndex < SINGLETON_PATH) {
+ currentIndex++;
+ return true;
+ } else if (!applicationType.singleton() && currentIndex < APP_DESC) {
+ currentIndex++;
+ return true;
+ } else {
+ currentIndex = -1;
+ return false;
+ }
+ }
+
+ public String getLabel() {
+ switch (currentIndex) {
+ case APP_TITLE:
+ return (String) GlobalizationUtil.globalize(
+ "ui.admin.applications.ApplicationInfoSection.title.label").
+ localize();
+ case APP_CLASS:
+ return (String) GlobalizationUtil.globalize(
+ "ui.admin.applications.ApplicationInfoSection.app_class.label").
+ localize();
+ case APP_SINGLETON:
+ return (String) GlobalizationUtil.globalize(
+ "ui.admin.applications.ApplicationInfoSection.singleton.label").
+ localize();
+ case APP_DESC:
+ return (String) GlobalizationUtil.globalize(
+ "ui.admin.applications.ApplicationInfoSection.desc.label").
+ localize();
+ case SINGLETON_PATH:
+ return (String) GlobalizationUtil.globalize(
+ "ui.admin.applications.ApplicationInfoSection.singleton_instance.path.label").
+ localize();
+ default:
+ return "unknown";
+ }
+ }
+
+ public GlobalizedMessage getGlobalizedLabel() {
+ switch (currentIndex) {
+ case APP_TITLE:
+ return GlobalizationUtil.globalize(
+ "ui.admin.applications.ApplicationInfoSection.title.label");
+ case APP_CLASS:
+ return GlobalizationUtil.globalize(
+ "ui.admin.applications.ApplicationInfoSection.app_class.label");
+ case APP_SINGLETON:
+ return GlobalizationUtil.globalize(
+ "ui.admin.applications.ApplicationInfoSection.singleton.label");
+ case APP_DESC:
+ return GlobalizationUtil.globalize(
+ "ui.admin.applications.ApplicationInfoSection.desc.label");
+ case SINGLETON_PATH:
+ return GlobalizationUtil.globalize(
+ "ui.admin.applications.ApplicationInfoSection.singleton_instance.path.label");
+ default:
+ return GlobalizationUtil.globalize("unknown");
+ }
+ }
+
+ @Override
+ public String getValue() {
+ switch (currentIndex) {
+ case APP_TITLE:
+ return applicationType.name();
+ case APP_CLASS:
+ return applicationType.name();
+ case APP_SINGLETON:
+ if (applicationType.singleton()) {
+ return (String) GlobalizationUtil.globalize(
+ "ui.admin.applications.ApplicationInfoSection.singleton.yes").
+ localize();
+ } else {
+ return (String) GlobalizationUtil.globalize(
+ "ui.admin.applications.ApplicationInfoSection.singleton.no").
+ localize();
+ }
+ case APP_DESC:
+ return applicationType.description();
+ case SINGLETON_PATH:
+ final String path;
+ final CdiUtil cdiUtil = new CdiUtil();
+ final ApplicationRepository appRepo;
+ try {
+ appRepo = cdiUtil.findBean(ApplicationRepository.class);
+ } catch (CdiLookupException ex) {
+ throw new UncheckedWrapperException(ex);
+ }
+ final List instances
+ = appRepo.findByType(
+ applicationType.name());
+ if (instances.isEmpty()) {
+ path = "";
+ } else {
+ path = instances.get(0).getPrimaryUrl();
+ }
+
+ return path;
+ default:
+ return "";
+ }
+ }
+
+}
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationInfoPropertySheetModelBuilder.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationInfoPropertySheetModelBuilder.java
new file mode 100644
index 000000000..b93d7ac95
--- /dev/null
+++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationInfoPropertySheetModelBuilder.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Jens Pelzetter
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.ui.admin.applications;
+
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.PropertySheet;
+import com.arsdigita.bebop.PropertySheetModel;
+import com.arsdigita.bebop.PropertySheetModelBuilder;
+import com.arsdigita.util.LockableImpl;
+import org.libreccm.web.ApplicationType;
+
+/**
+ * {@link PropertySheetModelBuilder} implementation for the the {@link ApplicationInfoPropertySheetModel}.
+ *
+ * @author Jens Pelzetter
+ * @version $Id: ApplicationInfoPropertySheetModelBuilder.java 2219 2013-06-19 08:16:11Z jensp $
+ */
+public class ApplicationInfoPropertySheetModelBuilder
+extends LockableImpl implements PropertySheetModelBuilder {
+
+ private final ApplicationType applicationType;
+
+ public ApplicationInfoPropertySheetModelBuilder(
+ final ApplicationType applicationType) {
+ super();
+ this.applicationType = applicationType;
+ }
+
+ @Override
+ public PropertySheetModel makeModel(final PropertySheet sheet,
+ final PageState state) {
+ return new ApplicationInfoPropertySheetModel(applicationType);
+ }
+
+}
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationInstanceAwareContainer.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationInstanceAwareContainer.java
new file mode 100644
index 000000000..a050eac29
--- /dev/null
+++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationInstanceAwareContainer.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013 Jens Pelzetter
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.ui.admin.applications;
+
+import com.arsdigita.bebop.SimpleContainer;
+import org.libreccm.web.CcmApplication;
+
+/**
+ *
+ * @author Jens Pelzetter
+ * @version $Id: ApplicationInstanceAwareContainer.java 2234 2013-06-29 12:41:57Z jensp $
+ */
+public class ApplicationInstanceAwareContainer extends SimpleContainer {
+
+ private CcmApplication appInstance;
+
+ public CcmApplication getAppInstance() {
+ return appInstance;
+ }
+
+ public void setAppInstance(final CcmApplication appInstance) {
+ this.appInstance = appInstance;
+ }
+
+}
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationInstancePane.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationInstancePane.java
new file mode 100644
index 000000000..19a23f5d7
--- /dev/null
+++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationInstancePane.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2013 Jens Pelzetter
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.ui.admin.applications;
+
+import com.arsdigita.bebop.Label;
+import com.arsdigita.bebop.PropertySheet;
+import com.arsdigita.bebop.SegmentedPanel;
+import com.arsdigita.bebop.event.PrintEvent;
+import com.arsdigita.bebop.event.PrintListener;
+import com.arsdigita.ui.admin.GlobalizationUtil;
+import org.libreccm.web.CcmApplication;
+
+
+
+/**
+ * This pane shows informations about a specific instance of a multi instance application, like
+ * title, parent application (if any) and the path. Also it contains a form for editing settings
+ * specific to the instance.
+ *
+ * @author Jens Pelzetter
+ * @version $Id$
+ */
+public class ApplicationInstancePane extends SegmentedPanel {
+
+ private CcmApplication application;
+ private final ApplicationInstanceAwareContainer appAdminPane;
+ private final ApplicationInstancePropertySheetModelBuilder modelBuilder;
+
+ public ApplicationInstancePane(
+ final ApplicationInstanceAwareContainer appAdminPane) {
+
+ super();
+ this.appAdminPane = appAdminPane;
+
+ modelBuilder = new ApplicationInstancePropertySheetModelBuilder();
+ final PropertySheet appInstInfoPanel = new PropertySheet(modelBuilder);
+
+ addSegment(new Label(GlobalizationUtil.globalize(
+ "ui.admin.applications.ApplicationInstancePane.info.heading")),
+ appInstInfoPanel);
+
+ if (appAdminPane == null) {
+
+ final Label noAdminPaneLabel = new Label();
+ noAdminPaneLabel.addPrintListener(new PrintListener() {
+ @Override
+ public void prepare(final PrintEvent event) {
+ final Label target = (Label) event.getTarget();
+
+ target.setLabel(GlobalizationUtil.globalize(
+ "ui.admin.MultiInstancePane.manage.no_instance_admin_pane_found",
+ new String[]{application.getApplicationType()}));
+ }
+
+ });
+
+ addSegment(new Label(GlobalizationUtil.globalize(
+ "ui.admin.MultiInstanceApplicationPane.manage.heading")),
+ noAdminPaneLabel);
+ } else {
+ //appAdminPane.setAppInstance(appInstance);
+ addSegment(new Label(GlobalizationUtil.globalize(
+ "ui.admin.applications.ApplicationInstancePane.manage.heading")),
+ appAdminPane);
+ }
+ }
+
+ public void setApplication(final CcmApplication application) {
+ this.application = application;
+ appAdminPane.setAppInstance(application);
+ modelBuilder.setApplication(application);
+ }
+
+}
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationInstancePropertySheetModel.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationInstancePropertySheetModel.java
new file mode 100644
index 000000000..0bda05ffd
--- /dev/null
+++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationInstancePropertySheetModel.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2013 Jens Pelzetter
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.ui.admin.applications;
+
+import com.arsdigita.bebop.PropertySheet;
+import com.arsdigita.bebop.PropertySheetModel;
+import com.arsdigita.globalization.GlobalizedMessage;
+import com.arsdigita.ui.admin.GlobalizationUtil;
+import org.libreccm.web.CcmApplication;
+
+/**
+ * A {@link PropertySheetModel} implementation for displaying informations about an instance of an application
+ * using a {@link PropertySheet}.
+ *
+ * @author Jens Pelzetter
+ * @version $Id: ApplicationInstancePropertySheetModel.java 2923 2014-10-27 18:55:26Z jensp $
+ */
+public class ApplicationInstancePropertySheetModel implements PropertySheetModel {
+
+ private static final int INST_TITLE = 0;
+ private static final int INST_PARENT = 1;
+ private static final int INST_PATH = 2;
+ private static final int INST_DESC = 3;
+ private final CcmApplication application;
+ private int currentIndex = -1;
+
+
+ public ApplicationInstancePropertySheetModel(final CcmApplication application) {
+ this.application = application;
+ }
+
+ @Override
+ public boolean nextRow() {
+ currentIndex++;
+ return currentIndex <= INST_DESC;
+ }
+
+ @Override
+ public String getLabel() {
+ switch (currentIndex) {
+ case INST_TITLE:
+ return (String) GlobalizationUtil.globalize("ui.admin.applications.ApplicationInstancePane.title.label").
+ localize();
+ case INST_PARENT:
+ return (String) GlobalizationUtil.globalize(
+ "ui.admin.applications.ApplicationInstancePane.parent_app.label").localize();
+ case INST_PATH:
+ return (String) GlobalizationUtil.globalize("ui.admin.applications.ApplicationInstancePane.path.label").
+ localize();
+ case INST_DESC:
+ return (String) GlobalizationUtil.globalize("ui.admin.applications.ApplicationInstancePane.desc.label").
+ localize();
+ default:
+ return "";
+ }
+ }
+
+ @Override
+ public GlobalizedMessage getGlobalizedLabel() {
+ switch (currentIndex) {
+ case INST_TITLE:
+ return GlobalizationUtil.globalize("ui.admin.applications.ApplicationInstancePane.title.label");
+ case INST_PARENT:
+ return GlobalizationUtil.globalize(
+ "ui.admin.applications.ApplicationInstancePane.parent_app.label");
+ case INST_PATH:
+ return GlobalizationUtil.globalize("ui.admin.applications.ApplicationInstancePane.path.label");
+ case INST_DESC:
+ return GlobalizationUtil.globalize("ui.admin.applications.ApplicationInstancePane.desc.label");
+ default:
+ return GlobalizationUtil.globalize("unknown");
+ }
+ }
+
+ @Override
+ public String getValue() {
+ switch (currentIndex) {
+ case INST_TITLE:
+ return application.getTitle().getValue();
+ case INST_PARENT:
+ if (application.getParent() == null) {
+ return "";
+ } else {
+ return application.getParent().getTitle().getValue();
+ }
+ case INST_PATH:
+ return application.getPrimaryUrl();
+ case INST_DESC:
+ return application.getDescription().getValue();
+ default:
+ return "";
+ }
+ }
+
+}
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationInstancePropertySheetModelBuilder.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationInstancePropertySheetModelBuilder.java
new file mode 100644
index 000000000..141dafba8
--- /dev/null
+++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationInstancePropertySheetModelBuilder.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 Jens Pelzetter
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.ui.admin.applications;
+
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.PropertySheet;
+import com.arsdigita.bebop.PropertySheetModel;
+import com.arsdigita.bebop.PropertySheetModelBuilder;
+import com.arsdigita.util.LockableImpl;
+import org.libreccm.web.CcmApplication;
+
+/**
+ * {@link PropertySheetModelBuilder} implementation for the {@link ApplicationInstancePropertySheetModel}.
+ *
+ * @author Jens Pelzetter
+ * @version $Id: ApplicationInstancePropertySheetModelBuilder.java 2293 2013-08-05 11:00:18Z jensp $
+ */
+public class ApplicationInstancePropertySheetModelBuilder
+extends LockableImpl implements PropertySheetModelBuilder {
+
+ private CcmApplication application;
+
+ public ApplicationInstancePropertySheetModelBuilder() {
+ super();
+ }
+
+ @Override
+ public PropertySheetModel makeModel(final PropertySheet sheet, final PageState state) {
+ return new ApplicationInstancePropertySheetModel(application);
+ }
+
+ public void setApplication(final CcmApplication application) {
+ this.application = application;
+ }
+
+}
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationManager.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationManager.java
new file mode 100644
index 000000000..f9c3208a9
--- /dev/null
+++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationManager.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2013 Jens Pelzetter
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.ui.admin.applications;
+
+import com.arsdigita.bebop.Form;
+import com.arsdigita.ui.admin.ApplicationsAdministrationTab;
+import java.util.ServiceLoader;
+import org.libreccm.web.CcmApplication;
+
+/**
+ * Implementations of this class are used by the new
+ * {@link ApplicationsAdministrationTab} to get the forms for editing the
+ * configuration of an application and for creating new instances of an
+ * application.
+ *
+ * The {@link ApplicationsAdministrationTab} uses the {@link ServiceLoader}
+ * from the Java Standard Library to find all implementations of this interface.
+ * To make implementations of this interface known add an file named
+ * {@code com.arsdigita.ui.admin.applications.ApplicationManager} to the
+ * {@code META-INF/services} directory of the module which provides the
+ * application. In this file add a line with the full qualified class name
+ * of each implementations of this interface provided by the module.
+ *
+ * There a two abstract classes to help you with implementing this class.
+ * {@link AbstractSingletonApplicationManager} is suitable for singleton
+ * applications. {@link AbstractApplicationManager} is for multi-instance
+ * applications.
+ *
+ * @param Type of the application for which this ApplicationManager
+ * provides the administration forms.
+ *
+ * @author Jens Pelzetter
+ * @version $Id: ApplicationManager.java 2275 2013-07-26 14:20:28Z jensp $
+ */
+public interface ApplicationManager {
+
+ /**
+ * Used to determine the Applications class for which this
+ * manager provides the administration forms.
+ *
+ * @return The class of the application for which this
+ * manager provides the administration forms.
+ */
+ Class getApplication();
+
+ /**
+ * Provides a pane with administration forms for the application or for an
+ * instance of the application if the application is not a singleton.
+ *
+ * @return A container containing one or more forms for managing instances
+ * of an application.
+ */
+ ApplicationInstanceAwareContainer getApplicationAdminForm();
+
+ /**
+ * Provides a form for creating new instances of applications. For
+ * singleton applications an implementation of this method will return
+ * {@code null}.
+ *
+ * @return A form for creating new instances of applications or
+ * {@code null} if the is a singleton.
+ */
+ Form getApplicationCreateForm();
+
+}
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/BaseApplicationPane.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/BaseApplicationPane.java
new file mode 100644
index 000000000..a98720a36
--- /dev/null
+++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/BaseApplicationPane.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013 Jens Pelzetter
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.ui.admin.applications;
+
+import com.arsdigita.bebop.Label;
+import com.arsdigita.bebop.PropertySheet;
+import com.arsdigita.bebop.SegmentedPanel;
+import com.arsdigita.ui.admin.GlobalizationUtil;
+import org.libreccm.web.ApplicationType;
+
+/**
+ * Basic application pane containing the parts common for singleton and multi instance applications types. Shows
+ * informations about a specific application type.
+ *
+ * @author Jens Pelzetter
+ * @version $Id$
+ */
+public class BaseApplicationPane extends SegmentedPanel {
+
+ public BaseApplicationPane(final ApplicationType applicationType) {
+ super();
+
+ final PropertySheet appInfoPanel = new PropertySheet(
+ new ApplicationInfoPropertySheetModelBuilder(
+ applicationType));
+ addSegment(new Label(GlobalizationUtil.globalize(
+ "ui.admin.applications.ApplicationInfoSection.heading")),
+ appInfoPanel);
+ }
+
+}
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/MultiInstanceApplicationPane.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/MultiInstanceApplicationPane.java
new file mode 100644
index 000000000..d49962952
--- /dev/null
+++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/MultiInstanceApplicationPane.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2013 Jens Pelzetter
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.ui.admin.applications;
+
+import com.arsdigita.bebop.Form;
+import com.arsdigita.bebop.Label;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.Table;
+import com.arsdigita.bebop.table.TableColumn;
+import com.arsdigita.bebop.table.TableModel;
+import com.arsdigita.bebop.table.TableModelBuilder;
+import com.arsdigita.ui.admin.GlobalizationUtil;
+import com.arsdigita.util.LockableImpl;
+import com.arsdigita.util.UncheckedWrapperException;
+import java.util.ArrayList;
+import java.util.List;
+import org.libreccm.cdi.utils.CdiLookupException;
+import org.libreccm.cdi.utils.CdiUtil;
+import org.libreccm.web.ApplicationRepository;
+import org.libreccm.web.ApplicationType;
+import org.libreccm.web.CcmApplication;
+
+/**
+ * Pane for multi instance applications. Additional to the data provided by
+ * {@link BaseApplicationPane} it shows a table of all instances of the
+ * application type and a form for creating new instances of the application
+ * type.
+ *
+ * @param
+ * @author Jens Pelzetter
+ * @version $Id$
+ */
+public class MultiInstanceApplicationPane
+ extends BaseApplicationPane {
+
+ private final static int COL_TITLE = 0;
+ private final static int COL_URL = 1;
+ private final static int COL_DESC = 2;
+
+ public MultiInstanceApplicationPane(final ApplicationType applicationType,
+ final Form createForm) {
+ super(applicationType);
+
+ //final ApplicationCollection applications = Application.retrieveAllApplications(applicationType.
+ // getApplicationObjectType());
+ //applications.rewind();
+ final Table table = new Table();
+ table.getColumnModel().add(
+ new TableColumn(COL_TITLE,
+ new Label(GlobalizationUtil.globalize(
+ "ui.admin.applicationsMultiInstanceApplicationPane.instances.table.col_title.header"))));
+ table.getColumnModel().add(
+ new TableColumn(COL_URL,
+ new Label(GlobalizationUtil.
+ globalize(
+ "ui.admin.applicationsMultiInstanceApplicationPane.instances.table.col_url.header"))));
+ table.getColumnModel().add(
+ new TableColumn(COL_DESC,
+ new Label(GlobalizationUtil.
+ globalize(
+ "ui.admin.applicationsMultiInstanceApplicationPane.instances.table.col_desc.header"))));
+
+ //table.setModelBuilder(new ApplicationInstancesTableModelBuilder(applications));
+ table.setModelBuilder(new ApplicationInstancesTableModelBuilder(
+ applicationType.name()));
+
+ addSegment(new Label(GlobalizationUtil.globalize(
+ "ui.admin.MultiInstanceApplicationPane.instances")),
+ table);
+
+ if (createForm == null) {
+ addSegment(new Label(GlobalizationUtil.globalize(
+ "ui.admin.MultiInstanceApplicationPane.manage_instances.heading")),
+ new Label(GlobalizationUtil.globalize(
+ "ui.admin.MultiInstancePane.manage.no_create_form_found",
+ new String[]{applicationType.name()})));
+ } else {
+ addSegment(new Label(GlobalizationUtil.globalize(
+ "ui.admin.MultiInstanceApplicationPane.create_instance")),
+ createForm);
+
+ }
+ }
+
+ private class ApplicationInstancesTableModelBuilder extends LockableImpl
+ implements TableModelBuilder {
+
+ //private final ApplicationCollection applications;
+ private final String appType;
+
+ //public ApplicationInstancesTableModelBuilder(final ApplicationCollection applications) {
+ // super();
+ //
+ // this.applications = applications;
+ //}
+ public ApplicationInstancesTableModelBuilder(final String appType) {
+ super();
+
+ //this.applications = Application.retrieveAllApplications(appType);
+ this.appType = appType;
+ }
+
+ @Override
+ public TableModel makeModel(final Table table, final PageState state) {
+ return new ApplicationInstancesTableModel(table, appType);
+ }
+ }
+
+ private class ApplicationInstancesTableModel implements TableModel {
+
+ private final Table table;
+ //private final ApplicationCollection applications;
+ private final List appData = new ArrayList<>();
+ private int currentIndex = -1;
+
+ //public ApplicationInstancesTableModel(final Table table, final ApplicationCollection applications) {
+ // this.table = table;
+ // this.applications = applications;
+ //}
+ public ApplicationInstancesTableModel(final Table table,
+ final String appType) {
+ this.table = table;
+ final CdiUtil cdiUtil = new CdiUtil();
+ final ApplicationRepository appRepo;
+ try {
+ appRepo = cdiUtil.findBean(ApplicationRepository.class);
+ } catch (CdiLookupException ex) {
+ throw new UncheckedWrapperException(ex);
+ }
+ final List applications = appRepo.
+ findByType(appType);
+ for (CcmApplication application : applications) {
+ addAppData(application);
+ }
+ }
+
+ private void addAppData(final CcmApplication application) {
+ appData.add(new AppData(application.getTitle().getValue(),
+ application.getDescription().getValue(),
+ application.getPrimaryUrl()));
+ }
+
+ @Override
+ public int getColumnCount() {
+ return table.getColumnModel().size();
+ }
+
+ @Override
+ public boolean nextRow() {
+ currentIndex++;
+ return currentIndex < appData.size();
+ }
+
+ @Override
+ public Object getElementAt(final int columnIndex) {
+ switch (columnIndex) {
+ case COL_TITLE:
+ //return applications.getApplication().getTitle();
+ return appData.get(currentIndex).getTitle();
+ case COL_DESC:
+ //return applications.getApplication().getDescription();
+ return appData.get(currentIndex).getDescription();
+ case COL_URL:
+ //return applications.getApplication().getPath();
+ return appData.get(currentIndex).getPath();
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public Object getKeyAt(final int columnIndex) {
+ //if (SessionManager.getSession().getTransactionContext().inTxn()) {
+ // SessionManager.getSession().getTransactionContext().commitTxn();
+ //}
+ //return applications.getApplication().getPath();
+ return appData.get(currentIndex).getPath();
+ }
+ }
+
+ private class AppData {
+
+ private final String title;
+ private final String description;
+ private final String path;
+
+ public AppData() {
+ title = "";
+ description = "";
+ path = "";
+ }
+
+ public AppData(final String title, final String description,
+ final String path) {
+ this.title = title;
+ this.description = description;
+ this.path = path;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getPath() {
+ return path;
+ }
+ }
+}
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/SingletonApplicationPane.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/SingletonApplicationPane.java
new file mode 100644
index 000000000..f43caca8f
--- /dev/null
+++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/SingletonApplicationPane.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013 Jens Pelzetter
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.ui.admin.applications;
+
+import com.arsdigita.bebop.Label;
+import com.arsdigita.bebop.SimpleContainer;
+import com.arsdigita.ui.admin.GlobalizationUtil;
+import org.libreccm.web.ApplicationType;
+
+/**
+ * Pane for managing singleton applications. Shows a form to edit application specific settings.
+ *
+ * @author Jens Pelzetter
+ * @version $Id$
+ */
+public class SingletonApplicationPane extends BaseApplicationPane {
+
+ public SingletonApplicationPane(final ApplicationType applicationType, final SimpleContainer appAdminPane) {
+ super(applicationType);
+
+ if (appAdminPane == null) {
+ addSegment(new Label(GlobalizationUtil.globalize(
+ "ui.admin.SingletonApplicationPane.manage.heading")),
+ new Label(GlobalizationUtil.globalize(
+ "ui.admin.SingletonApplicationPane.manage.no_admin_pane_found",
+ new String[]{applicationType.name()})));
+ } else {
+ addSegment(new Label(GlobalizationUtil.globalize(
+ "ui.admin.SingletonApplicationPane.manage.heading")),
+ appAdminPane);
+ }
+ }
+
+}
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/tree/ApplicationInstanceTreeNode.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/tree/ApplicationInstanceTreeNode.java
new file mode 100644
index 000000000..cdf47e0c8
--- /dev/null
+++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/tree/ApplicationInstanceTreeNode.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2013 Jens Pelzetter
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.ui.admin.applications.tree;
+
+import com.arsdigita.bebop.tree.TreeNode;
+import com.arsdigita.ui.admin.ApplicationsAdministrationTab;
+import org.libreccm.web.CcmApplication;
+
+/**
+ * Tree Node for the application tree representing an instance of a application.
+ *
+ * @author Jens Pelzetter
+ * @version $Id: ApplicationInstanceTreeNode.java 2282 2013-08-01 10:45:42Z jensp $
+ *
+ * @see ApplicationTreeModel
+ * @see ApplicationTreeModelBuilder
+ * @see ApplicationTypeTreeNode
+ * @see ApplicationsAdministrationTab
+ * @see TreeNode
+ */
+public class ApplicationInstanceTreeNode implements TreeNode {
+
+ /**
+ * The application instance represented by this {@code TreeNode}
+ */
+ //private final Application application;
+ private final String path;
+ private final String title;
+ private final String appType;
+
+ /**
+ * Constructor
+ *
+ * @param application The application instance to represent by this {@code TreeNode}
+ */
+ public ApplicationInstanceTreeNode(final CcmApplication application) {
+ //this.application = application;
+ path = application.getPrimaryUrl();
+ title = application.getTitle().getValue();
+ appType = application.getClass().getName();
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getAppType() {
+ return appType;
+ }
+
+ /**
+ * Returns the key for this {@link TreeNode}.
+ *
+ * @return The path of the application instance.
+ * @see TreeNode#getKey()
+ */
+ @Override
+ public Object getKey() {
+ //return application.getPath();
+ return path;
+ }
+
+ /**
+ * Data to show in the tree for this node.
+ *
+ * @return The title of the application instance
+ * @see TreeNode#getElement()
+ */
+ @Override
+ public Object getElement() {
+ //return application.getTitle();
+ return title;
+ }
+
+}
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/tree/ApplicationTreeModel.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/tree/ApplicationTreeModel.java
new file mode 100644
index 000000000..f3c064982
--- /dev/null
+++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/tree/ApplicationTreeModel.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2013 Jens Pelzetter
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.ui.admin.applications.tree;
+
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.tree.TreeModel;
+import com.arsdigita.bebop.tree.TreeNode;
+import com.arsdigita.ui.admin.ApplicationsAdministrationTab;
+import com.arsdigita.util.UncheckedWrapperException;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import org.libreccm.cdi.utils.CdiLookupException;
+import org.libreccm.cdi.utils.CdiUtil;
+import org.libreccm.web.ApplicationManager;
+import org.libreccm.web.ApplicationRepository;
+import org.libreccm.web.ApplicationType;
+import org.libreccm.web.CcmApplication;
+
+/**
+ * A {@link TreeModel} for the tree of applications in {@link ApplicationsAdministrationTab}. The tree consists of two
+ * different types of nodes: Nodes for {@link ApplicationTypes} and nodes for {@link Application} instances.
+ *
+ * @author Jens Pelzetter
+ * @version $Id: ApplicationTreeModel.java 2406 2013-10-31 19:52:22Z jensp $
+ */
+public class ApplicationTreeModel implements TreeModel {
+
+ public ApplicationTreeModel() {
+ //Nothing
+ }
+
+ @Override
+ public TreeNode getRoot(final PageState state) {
+ return new RootTreeNode();
+ }
+
+ @Override
+ public boolean hasChildren(final TreeNode node, final PageState state) {
+ if (node instanceof RootTreeNode) {
+ return true;
+ } else if (node instanceof ApplicationTypeTreeNode) {
+ final ApplicationTypeTreeNode typeTreeNode = (ApplicationTypeTreeNode) node;
+
+ //if (typeTreeNode.getApplicationType().isSingleton()) {
+ if (typeTreeNode.isSingleton()) {
+ return false;
+ } else {
+ //return !retrieveApplicationInstances(typeTreeNode.getApplicationType()).isEmpty();
+ //return !retrieveApplicationInstances(typeTreeNode.getApplicationType()).isEmpty();
+ return !retrieveApplicationInstances(typeTreeNode.getObjecType()).isEmpty();
+ }
+ } else if (node instanceof ApplicationInstanceTreeNode) {
+ return false;
+ } else {
+ throw new IllegalArgumentException(
+ "The ApplicationTreeModel can only work with ApplicationTypeTreeNodes and"
+ + "ApplicationInstanceTreeNodes.");
+ }
+ }
+
+ @Override
+ public Iterator getChildren(final TreeNode node, final PageState state) {
+ if (node instanceof RootTreeNode) {
+ final CdiUtil cdiUtil = new CdiUtil();
+ final ApplicationManager appManager;
+ try {
+ appManager = cdiUtil.findBean(ApplicationManager.class);
+ } catch(CdiLookupException ex) {
+ throw new UncheckedWrapperException(ex);
+ }
+
+ final Collection appTypes = appManager.getApplicationTypes().values();
+
+ return new AppTypesIterator(appTypes);
+ } else if (node instanceof ApplicationTypeTreeNode) {
+ final ApplicationTypeTreeNode typeTreeNode = (ApplicationTypeTreeNode) node;
+
+ final CdiUtil cdiUtil = new CdiUtil();
+ final ApplicationRepository appRepo;
+ try {
+ appRepo = cdiUtil.findBean(ApplicationRepository.class);
+ } catch(CdiLookupException ex) {
+ throw new UncheckedWrapperException(ex);
+ }
+
+ final List applications = appRepo.findByType(
+ typeTreeNode.getObjecType());
+
+ return new AppIterator(applications);
+ } else if (node instanceof ApplicationInstanceTreeNode) {
+ return null;
+ } else {
+ throw new IllegalArgumentException(
+ "The ApplicationTreeModel can only work with ApplicationTypeTreeNodes and"
+ + "ApplicationInstanceTreeNodes.");
+ }
+ }
+
+ private List retrieveApplicationInstances(
+ final ApplicationType applicationType) {
+ final CdiUtil cdiUtil = new CdiUtil();
+ final ApplicationRepository appRepo;
+ try {
+ appRepo = cdiUtil.findBean(ApplicationRepository.class);
+ } catch(CdiLookupException ex) {
+ throw new UncheckedWrapperException(ex);
+ }
+
+ return appRepo.findByType(applicationType.name());
+ }
+
+ private List retrieveApplicationInstances(
+ final String appObjectType) {
+ final CdiUtil cdiUtil = new CdiUtil();
+ final ApplicationRepository appRepo;
+ try {
+ appRepo = cdiUtil.findBean(ApplicationRepository.class);
+ } catch(CdiLookupException ex) {
+ throw new UncheckedWrapperException(ex);
+ }
+
+ return appRepo.findByType(appObjectType);
+ }
+
+ private class RootTreeNode implements TreeNode {
+
+ public RootTreeNode() {
+ //Nothing
+ }
+
+ @Override
+ public Object getKey() {
+ return "-1";
+ }
+
+ @Override
+ public Object getElement() {
+ return "/";
+ }
+
+ }
+
+ private class AppTypesIterator implements Iterator {
+
+ private final Iterator appTypes;
+
+ public AppTypesIterator(final Collection appTypes) {
+ this.appTypes = appTypes.iterator();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return appTypes.hasNext();
+ }
+
+ @Override
+ public ApplicationTypeTreeNode next() {
+ return new ApplicationTypeTreeNode(appTypes.next());
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ }
+
+ private class AppIterator implements Iterator {
+
+ private final Iterator applications;
+
+ public AppIterator(final Collection applications) {
+ this.applications = applications.iterator();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return applications.hasNext();
+ }
+
+ @Override
+ public ApplicationInstanceTreeNode next() {
+ return new ApplicationInstanceTreeNode(applications.next());
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ }
+}
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/tree/ApplicationTreeModelBuilder.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/tree/ApplicationTreeModelBuilder.java
new file mode 100644
index 000000000..a388ad6d3
--- /dev/null
+++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/tree/ApplicationTreeModelBuilder.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013 Jens Pelzetter
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.ui.admin.applications.tree;
+
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.Tree;
+import com.arsdigita.bebop.tree.TreeModel;
+import com.arsdigita.bebop.tree.TreeModelBuilder;
+import com.arsdigita.ui.admin.ApplicationsAdministrationTab;
+import com.arsdigita.util.LockableImpl;
+
+/**
+ * The {@link TreeModelBuilder} creating the {@link TreeModel} for the
+ * applications tree used in {@link ApplicationsAdministrationTab}.
+ *
+ * @author Jens Pelzetter
+ * @version $Id: ApplicationTreeModelBuilder.java 2294 2013-08-05 18:39:46Z
+ * jensp $
+ */
+public class ApplicationTreeModelBuilder extends LockableImpl
+ implements TreeModelBuilder {
+
+ @Override
+ public TreeModel makeModel(final Tree tree, final PageState state) {
+ tree.expand("-1", state);
+ return new ApplicationTreeModel();
+ }
+}
diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/tree/ApplicationTypeTreeNode.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/tree/ApplicationTypeTreeNode.java
new file mode 100644
index 000000000..14e0540a3
--- /dev/null
+++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/tree/ApplicationTypeTreeNode.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013 Jens Pelzetter
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+package com.arsdigita.ui.admin.applications.tree;
+
+import com.arsdigita.bebop.tree.TreeNode;
+import java.math.BigDecimal;
+import org.libreccm.web.ApplicationType;
+
+/**
+ * Tree Node implementation for the Application Tree in the Application admin tab.
+ *
+ * @author Jens Pelzetter
+ * @version $Id: ApplicationTypeTreeNode.java 2282 2013-08-01 10:45:42Z jensp $
+ */
+public class ApplicationTypeTreeNode implements TreeNode {
+
+ private final String name;
+ private final String objectType;
+ private final boolean singleton;
+ private final String description;
+ // Needed:
+ // isSingleton
+ // getObjectType
+
+ public ApplicationTypeTreeNode(final ApplicationType applicationType) {
+ //this.applicationType = applicationType;
+ name = applicationType.name();
+ objectType = applicationType.name();
+ singleton = applicationType.singleton();
+ description = applicationType.description();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getObjecType() {
+ return objectType;
+ }
+
+ public boolean isSingleton() {
+ return singleton;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public Object getKey() {
+ //return applicationType.getApplicationObjectType();
+ return objectType;
+ }
+
+ public Object getElement() {
+ return name;
+ }
+}
diff --git a/ccm-shortcuts/pom.xml b/ccm-shortcuts/pom.xml
index 3b9d6a1d1..7bd69adf4 100644
--- a/ccm-shortcuts/pom.xml
+++ b/ccm-shortcuts/pom.xml
@@ -208,9 +208,11 @@
-
- src/main/resources
- true
+
+
+ src/main/resources
+ true
+