diff --git a/ccm-cms/src/com/arsdigita/cms/contenttypes/GenericOrganizationalUnit.java b/ccm-cms/src/com/arsdigita/cms/contenttypes/GenericOrganizationalUnit.java
index ab5abe466..58f3ea401 100644
--- a/ccm-cms/src/com/arsdigita/cms/contenttypes/GenericOrganizationalUnit.java
+++ b/ccm-cms/src/com/arsdigita/cms/contenttypes/GenericOrganizationalUnit.java
@@ -21,6 +21,8 @@ package com.arsdigita.cms.contenttypes;
import com.arsdigita.cms.ContentBundle;
import com.arsdigita.cms.ContentPage;
+import com.arsdigita.cms.ExtraXMLGenerator;
+import com.arsdigita.cms.contenttypes.ui.GenericOrgaUnitExtraXmlGenerator;
import com.arsdigita.cms.contenttypes.ui.GenericOrganizationalUnitSubordinateOrgaUnitAddForm;
import com.arsdigita.cms.contenttypes.ui.GenericOrganizationalUnitSubordinateOrgaUnitsTable;
import com.arsdigita.cms.ui.authoring.AuthoringKitWizard;
@@ -30,6 +32,7 @@ import com.arsdigita.persistence.DataObject;
import com.arsdigita.persistence.OID;
import com.arsdigita.util.Assert;
import java.math.BigDecimal;
+import java.util.List;
import org.apache.log4j.Logger;
/**
@@ -77,7 +80,7 @@ public class GenericOrganizationalUnit extends ContentPage {
public GenericOrganizationalUnit(final String type) {
super(type);
}
-
+
public String getAddendum() {
return (String) get(ADDENDUM);
}
diff --git a/ccm-cms/src/com/arsdigita/cms/contenttypes/ui/GenericOrgaUnitContactsTab.java b/ccm-cms/src/com/arsdigita/cms/contenttypes/ui/GenericOrgaUnitContactsTab.java
new file mode 100644
index 000000000..65886acef
--- /dev/null
+++ b/ccm-cms/src/com/arsdigita/cms/contenttypes/ui/GenericOrgaUnitContactsTab.java
@@ -0,0 +1,79 @@
+package com.arsdigita.cms.contenttypes.ui;
+
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.cms.ContentItem;
+import com.arsdigita.cms.contenttypes.GenericContact;
+import com.arsdigita.cms.contenttypes.GenericOrganizationalUnit;
+import com.arsdigita.cms.contenttypes.GenericOrganizationalUnitContactCollection;
+import com.arsdigita.cms.dispatcher.SimpleXMLGenerator;
+import com.arsdigita.xml.Element;
+
+/**
+ *
+ * @author Jens Pelzetter
+ * @version $Id$
+ */
+public class GenericOrgaUnitContactsTab implements GenericOrgaUnitTab {
+
+ @Override
+ public boolean hasData(final GenericOrganizationalUnit orgaunit) {
+ return !getData(orgaunit).isEmpty();
+ }
+
+ @Override
+ public void generateXml(final GenericOrganizationalUnit orgaunit,
+ final Element parent,
+ final PageState state) {
+ final GenericOrganizationalUnitContactCollection contacts = getData(orgaunit,
+ state);
+
+ Element contactsElem = parent.newChildElement("contacts");
+ while (contacts.next()) {
+ GenericContact contact;
+ contact = contacts.getContact();
+
+ generateGenericContactXML(contact,
+ contactsElem,
+ state,
+ Integer.toString(
+ contacts.getContactOrder()),
+ true);
+ }
+ }
+
+ protected void generateGenericContactXML(final GenericContact contact,
+ final Element parent,
+ final PageState state,
+ final String order,
+ final boolean withPerson) {
+ ContactXmlLGenerator generator = new ContactXmlLGenerator(contact);
+
+ generator.generateXML(state, parent, order);
+ }
+
+ protected GenericOrganizationalUnitContactCollection getData(
+ final GenericOrganizationalUnit orgaunit,
+ final PageState state) {
+ return getData(orgaunit);
+ }
+
+ protected GenericOrganizationalUnitContactCollection getData(
+ final GenericOrganizationalUnit orgaunit) {
+ return orgaunit.getContacts();
+ }
+
+ private class ContactXmlLGenerator extends SimpleXMLGenerator {
+
+ private GenericContact contact;
+
+ public ContactXmlLGenerator(final GenericContact contact) {
+ super();
+ this.contact = contact;
+ }
+
+ @Override
+ protected ContentItem getContentItem(PageState state) {
+ return contact;
+ }
+ }
+}
diff --git a/ccm-cms/src/com/arsdigita/cms/contenttypes/ui/GenericOrgaUnitExtraXmlGenerator.java b/ccm-cms/src/com/arsdigita/cms/contenttypes/ui/GenericOrgaUnitExtraXmlGenerator.java
new file mode 100644
index 000000000..854f571fc
--- /dev/null
+++ b/ccm-cms/src/com/arsdigita/cms/contenttypes/ui/GenericOrgaUnitExtraXmlGenerator.java
@@ -0,0 +1,215 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.arsdigita.cms.contenttypes.ui;
+
+import com.arsdigita.bebop.Page;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.cms.ContentItem;
+import com.arsdigita.cms.ContentPage;
+import com.arsdigita.cms.ExtraXMLGenerator;
+import com.arsdigita.cms.contenttypes.GenericOrganizationalUnit;
+import com.arsdigita.xml.Element;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import org.apache.log4j.Logger;
+
+/**
+ *
+ * Base class for {@link ExtraXMLGenerator}s for sub classes of
+ * {@link GenericOrganizationalUnit}. The only method which has to be
+ * overwritten is {@link #getTabConfig()}. This method will return the tabs
+ * (instances of implementations of {@link GenericOrgaUnitTab}). The
+ * {@link #generateXML(com.arsdigita.cms.ContentItem, com.arsdigita.xml.Element, com.arsdigita.bebop.PageState)}
+ * method delegates the XML creation to this objects.
+ *
+ *
+ * {@link GenericOrganizationalUnit} does not include this generator.
+ * The subclasses of {@link GenericOrganizationalUnit} are responsible for
+ * integrating the subclasses of this class by overwriting the
+ * {@link ContentPage#getExtraXMLGenerators()}.
+ *
+ *
+ * @author Jens Pelzetter
+ * @version $Id$
+ */
+public abstract class GenericOrgaUnitExtraXmlGenerator
+ implements ExtraXMLGenerator {
+
+ private final static Logger logger =
+ Logger.getLogger(
+ GenericOrgaUnitExtraXmlGenerator.class);
+ private final static String SELECTED_TAB_PARAM = "selectedTab";
+ private String showOnly;
+
+ public void generateXML(final ContentItem item,
+ final Element element,
+ final PageState state) {
+ final long start = System.currentTimeMillis();
+ if (!(item instanceof GenericOrganizationalUnit)) {
+ throw new IllegalArgumentException(
+ "This ExtraXMLGenerator supports "
+ + "only instances of GenericOrganizationalUnit only.");
+ }
+
+ final Element orgaUnitTabsElem = element.newChildElement("orgaUnitTabs");
+
+ final Element availableTabsElem = orgaUnitTabsElem.newChildElement(
+ "availableTabs");
+
+ final GenericOrganizationalUnit orgaunit =
+ (GenericOrganizationalUnit) item;
+ final Map tabs =
+ processTabConfig(getTabConfig());
+ String selected = state.getRequest().getParameter(
+ SELECTED_TAB_PARAM);
+ if (showOnly != null && !showOnly.isEmpty()) {
+ selected = showOnly;
+ }
+ if ((selected == null) || selected.isEmpty()) {
+ selected = new ArrayList(tabs.keySet()).get(0);
+ }
+ final long availableStart = System.currentTimeMillis();
+ if ((showOnly == null) || showOnly.isEmpty()) {
+ for (Map.Entry entry : tabs.entrySet()) {
+ if (entry.getValue().hasData(orgaunit)) {
+ createAvailableTabElem(availableTabsElem,
+ entry.getKey(),
+ selected);
+ }
+ }
+ }
+ logger.debug(String.format("Created available tabs XML for "
+ + "GenericOrganizationalUnit '%s' in %d ms.",
+ orgaunit.getName(),
+ System.currentTimeMillis() - availableStart));
+
+ if (tabs.containsKey(selected) && tabs.get(selected).hasData(orgaunit)) {
+ final GenericOrgaUnitTab selectedTab = tabs.get(selected);
+ final Element selectedTabElem = orgaUnitTabsElem.newChildElement(
+ "selectedTab");
+ selectedTab.generateXml(orgaunit, selectedTabElem, state);
+ } else {
+ orgaUnitTabsElem.newChildElement("selectedTabNotAvailable");
+ }
+
+ logger.debug(String.format("Generated XML for GenericOrganizationalUnit "
+ + "'%s' in %d ms",
+ orgaunit.getName(),
+ System.currentTimeMillis() - start));
+ }
+
+ /**
+ * Can be used from a JSP template for Navigation to show only a specific
+ * tab in category.
+ *
+ * @param showOnly
+ */
+ public void setShowOnly(final String showOnly) {
+ this.showOnly = showOnly;
+ }
+
+ private void createAvailableTabElem(final Element parent,
+ final String key,
+ final String selected) {
+ final Element availableTabElem = parent.newChildElement("availableTab");
+ availableTabElem.addAttribute("label", key);
+ if (key.equals(selected)) {
+ availableTabElem.addAttribute("selected", "true");
+ } else {
+ availableTabElem.addAttribute("selected", "false");
+ }
+ }
+
+ /**
+ *
+ * This method should return a string containing all tabs to use. The string
+ * must have to following format:
+ *
+ *
+ *
+ * tabName:fullyQualifedClassName;...
+ *
+ *
+ *
+ * Example:
+ *
+ *
+ *
+ * foo:com.arsdigita.cms.contenttypes.ui.FooTab;bar:com.arsdigita.cms.contenttypes.BarTab;fooBar:com.arsdigita.cms.contenttypes.ui.FooBarTab
+ *
+ *
+ *
+ * @return
+ */
+ public abstract String getTabConfig();
+
+ private Map processTabConfig(
+ final String tabConfig) {
+ final long start = System.currentTimeMillis();
+ final String[] tokens = tabConfig.split(";");
+
+ final Map tabs =
+ new LinkedHashMap();
+
+ for (String token : tokens) {
+ processTabConfigToken(tabs, token);
+ }
+
+ logger.debug(String.format("Processed tab config in %d ms",
+ System.currentTimeMillis() - start));
+ return tabs;
+ }
+
+ @SuppressWarnings("unchecked")
+ private void processTabConfigToken(
+ final Map tabs,
+ final String tabConfigToken) {
+ final String[] tokens = tabConfigToken.split(":");
+
+ if (tokens.length != 2) {
+ throw new IllegalArgumentException(String.format(
+ "Invalid tab configuration token. Found more or less than"
+ + "two tokens in string '%s'.",
+ tabConfigToken));
+ }
+
+ final String tabName = tokens[0];
+ final String tabClassName = tokens[1];
+ final GenericOrgaUnitTab tab = createTabInstance(tabClassName);
+ tabs.put(tabName, tab);
+ }
+
+ @SuppressWarnings("unchecked")
+ private GenericOrgaUnitTab createTabInstance(final String tabClassName) {
+ final GenericOrgaUnitTab tab;
+
+ try {
+ tab = (GenericOrgaUnitTab) Class.forName(tabClassName).
+ newInstance();
+ } catch (ClassNotFoundException ex) {
+ throw new IllegalArgumentException(String.format(
+ "Can't find tab class '%s'.",
+ tabClassName),
+ ex);
+ } catch (InstantiationException ex) {
+ throw new IllegalArgumentException(String.format(
+ "Can't instantiate tab class '%s'.",
+ tabClassName),
+ ex);
+ } catch (IllegalAccessException ex) {
+ throw new IllegalArgumentException(String.format(
+ "Can't instantiate tab class '%s'.",
+ tabClassName),
+ ex);
+ }
+
+ return tab;
+ }
+
+ public void addGlobalStateParams(final Page page) {
+ //Nothing yet
+ }
+}
diff --git a/ccm-cms/src/com/arsdigita/cms/contenttypes/ui/GenericOrgaUnitPaginator.java b/ccm-cms/src/com/arsdigita/cms/contenttypes/ui/GenericOrgaUnitPaginator.java
new file mode 100644
index 000000000..de2e20f2e
--- /dev/null
+++ b/ccm-cms/src/com/arsdigita/cms/contenttypes/ui/GenericOrgaUnitPaginator.java
@@ -0,0 +1,144 @@
+package com.arsdigita.cms.contenttypes.ui;
+
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.domain.DomainCollection;
+import com.arsdigita.web.ParameterMap;
+import com.arsdigita.web.URL;
+import com.arsdigita.web.Web;
+import com.arsdigita.xml.Element;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Helper class for generating a paginator in lists generated by
+ * {@link GenericOrgaUnitTab}s.
+ *
+ * @param
+ * @author Jens Pelzetter
+ * @version $Id$
+ */
+public class GenericOrgaUnitPaginator {
+
+ private final static String PAGE_NUMBER = "pageNumber";
+ private final long pageSize;
+ private final long pageCount;
+ private final long begin;
+ private final long count;
+ private final long end;
+ private final long pageNumber;
+
+ public GenericOrgaUnitPaginator(final T collection,
+ final PageState state,
+ final long pageSize) {
+ this.pageSize = pageSize;
+
+ final long pageNum = getPageNumber(state);
+
+ pageCount = getPageCount(collection.size());
+ begin = getPaginatorBegin(pageNum);
+ count = getPaginatorCount(begin, collection.size());
+ end = getPaginatorEnd(begin, count);
+ pageNumber = normalizePageNumber(pageCount, pageNum);
+ }
+
+ public void setRange(final T collection) {
+ collection.setRange((int) begin + 1, (int) end + 1);
+ }
+
+ public void generateXml(final Element parent) {
+ final Element paginatorElem = parent.newChildElement(
+ "nav:paginator",
+ "http://ccm.redhat.com/london/navigation");
+
+ final URL requestUrl = Web.getContext().getRequestURL();
+ final ParameterMap parameters = new ParameterMap();
+ if (requestUrl.getParameterMap() != null) {
+
+ Iterator> current =
+ requestUrl.getParameterMap().keySet().iterator();
+ while (current.hasNext()) {
+ final String key = (String) current.next();
+ if (PAGE_NUMBER.equals(key)) {
+ continue;
+ } else {
+ parameters.setParameter(key, requestUrl.getParameterValues(
+ key));
+ }
+ }
+ }
+
+ paginatorElem.addAttribute("pageParam", "pageNumber");
+ paginatorElem.addAttribute("baseURL", URL.there(requestUrl.getPathInfo(),
+ parameters).toString());
+ paginatorElem.addAttribute("pageNumber", Long.toString(pageNumber));
+ paginatorElem.addAttribute("pageCount", Long.toString(pageCount));
+ paginatorElem.addAttribute("pageSize", Long.toString(pageSize));
+ paginatorElem.addAttribute("objectBegin", Long.toString(begin + 1));
+ paginatorElem.addAttribute("objectEnd", Long.toString(end + 1));
+ paginatorElem.addAttribute("objectCount", Long.toString(count));
+
+ }
+
+ private long getPageNumber(final PageState state) {
+ long num = 1;
+
+ if (state == null) {
+ return num;
+ }
+
+
+ final String value = state.getRequest().getParameter(PAGE_NUMBER);
+ if (value != null) {
+ try {
+ num = Integer.parseInt(value);
+ } catch (NumberFormatException ex) {
+ num = 1;
+ }
+ }
+
+ return num;
+ }
+
+ private long normalizePageNumber(final long pageCount,
+ final long pageNumber) {
+ long num = pageNumber;
+ if (num < 1) {
+ num = 1;
+ }
+ if (num > pageCount) {
+ if (pageCount == 0) {
+ num = 1;
+ } else {
+ num = pageCount;
+ }
+ }
+
+ return num;
+ }
+
+ private long getPageCount(final long objectCount) {
+ final double dObjectCount = (double) objectCount;
+ final double dPageSize = (double) pageSize;
+
+ final double dResult = Math.ceil(dObjectCount / pageSize);
+ final long result = (long) dResult;
+
+ return result;
+ }
+
+ private long getPaginatorBegin(final long pageNumber) {
+ return (pageNumber - 1) * pageSize;
+ }
+
+ private long getPaginatorCount(final long begin, final long objectCount) {
+ return Math.min(pageSize, (objectCount - begin));
+ }
+
+ private long getPaginatorEnd(final long begin, final long count) {
+ long paginatorEnd = begin + count;
+ if (paginatorEnd < 0) {
+ paginatorEnd = 0;
+ }
+ return paginatorEnd;
+ }
+}
diff --git a/ccm-cms/src/com/arsdigita/cms/contenttypes/ui/GenericOrgaUnitSubordinateTab.java b/ccm-cms/src/com/arsdigita/cms/contenttypes/ui/GenericOrgaUnitSubordinateTab.java
new file mode 100644
index 000000000..996dfdd14
--- /dev/null
+++ b/ccm-cms/src/com/arsdigita/cms/contenttypes/ui/GenericOrgaUnitSubordinateTab.java
@@ -0,0 +1,153 @@
+package com.arsdigita.cms.contenttypes.ui;
+
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.cms.ContentItem;
+import com.arsdigita.cms.contenttypes.GenericOrganizationalUnit;
+import com.arsdigita.cms.contenttypes.GenericOrganizationalUnitSubordinateCollection;
+import com.arsdigita.cms.dispatcher.SimpleXMLGenerator;
+import com.arsdigita.xml.Element;
+import org.apache.log4j.Logger;
+
+/**
+ *
+ * @author Jens Pelzetter
+ * @version $Id$
+ */
+public abstract class GenericOrgaUnitSubordinateTab
+ implements GenericOrgaUnitTab {
+
+ private final static Logger logger =
+ Logger.getLogger(
+ GenericOrgaUnitSubordinateTab.class);
+
+ @Override
+ public boolean hasData(final GenericOrganizationalUnit orgaunit) {
+ return !getData(orgaunit).isEmpty();
+ }
+
+ @Override
+ public void generateXml(final GenericOrganizationalUnit orgaunit,
+ final Element parent,
+ final PageState state) {
+ final long start = System.currentTimeMillis();
+ final GenericOrganizationalUnitSubordinateCollection subOrgaUnits =
+ getData(orgaunit,
+ state);
+
+ processFilters(subOrgaUnits, state);
+
+ final Element subOrgaUnitsElem =
+ parent.newChildElement(getXmlElementName());
+
+ if (getPageSize() != 0) {
+ final GenericOrgaUnitPaginator paginator =
+ new GenericOrgaUnitPaginator(
+ subOrgaUnits, state, getPageSize());
+ paginator.setRange(subOrgaUnits);
+ paginator.generateXml(subOrgaUnitsElem);
+ }
+
+ while (subOrgaUnits.next()) {
+ generateSubOrgaUnitXml(subOrgaUnits.getGenericOrganizationalUnit(),
+ parent,
+ state);
+ }
+ logger.debug(String.format("XML for subordinate organizational units of "
+ + "organizational unit '%s' with assoctype '%s' generated in"
+ + "%d ms",
+ orgaunit.getName(),
+ getAssocType(),
+ System.currentTimeMillis() - start));
+ }
+
+ private void generateSubOrgaUnitXml(
+ final GenericOrganizationalUnit orgaunit,
+ final Element parent,
+ final PageState state) {
+ final SubordinateXmlLGenerator generator = new SubordinateXmlLGenerator(
+ orgaunit);
+ generator.generateXML(state, parent, "");
+ }
+
+ protected GenericOrganizationalUnitSubordinateCollection getData(
+ final GenericOrganizationalUnit orgaunit,
+ final PageState state) {
+ return getData(orgaunit);
+ }
+
+ protected GenericOrganizationalUnitSubordinateCollection getData(
+ final GenericOrganizationalUnit orgaunit) {
+ final GenericOrganizationalUnitSubordinateCollection subOrgaUnits =
+ orgaunit.
+ getSubordinateOrgaUnits();
+ subOrgaUnits.addFilter(
+ String.format("%s = '%s'",
+ GenericOrganizationalUnitSubordinateCollection.LINK_ASSOCTYPE,
+ getAssocType()));
+
+ return subOrgaUnits;
+ }
+
+ protected abstract String getXmlElementName();
+
+ /**
+ * The collection of subordinate organization units is filtered for
+ * the value of the {@code assocType} property returned by this method.
+ * If you don't want to filter for an assocType simply return '{@code %}'.
+ *
+ * @return
+ */
+ protected abstract String getAssocType();
+
+ /**
+ * Page size for the paginator. If you want to disable the paginator,
+ * return 0.
+ *
+ * @return
+ */
+ protected abstract int getPageSize();
+
+ /**
+ * Overwrite to create filters for the list.
+ *
+ * @param orgaunit
+ * @param subOrgaUnits
+ * @param element
+ * @param state
+ */
+ protected void generateFiltersXml(
+ final GenericOrganizationalUnit orgaunit,
+ final GenericOrganizationalUnitSubordinateCollection subOrgaUnits,
+ final Element element,
+ final PageState state) {
+ //Nothing now
+ }
+
+ /**
+ * If you have filters for the list of subordinate organizational units,
+ * overwrite this method to process them.
+ *
+ * @param subOrgaUnits
+ * @param state
+ */
+ protected void processFilters(
+ final GenericOrganizationalUnitSubordinateCollection subOrgaUnits,
+ final PageState state) {
+ //Nothing now
+ }
+
+ private class SubordinateXmlLGenerator extends SimpleXMLGenerator {
+
+ private final GenericOrganizationalUnit orgaunit;
+
+ public SubordinateXmlLGenerator(final GenericOrganizationalUnit orgaunit) {
+ super();
+ this.orgaunit = orgaunit;
+ }
+
+ @Override
+ protected ContentItem getContentItem(final PageState state) {
+ return orgaunit;
+ }
+ }
+}
diff --git a/ccm-cms/src/com/arsdigita/cms/contenttypes/ui/GenericOrgaUnitTab.java b/ccm-cms/src/com/arsdigita/cms/contenttypes/ui/GenericOrgaUnitTab.java
new file mode 100644
index 000000000..050752222
--- /dev/null
+++ b/ccm-cms/src/com/arsdigita/cms/contenttypes/ui/GenericOrgaUnitTab.java
@@ -0,0 +1,20 @@
+package com.arsdigita.cms.contenttypes.ui;
+
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.cms.contenttypes.GenericOrganizationalUnit;
+import com.arsdigita.xml.Element;
+
+/**
+ *
+ * @author Jens Pelzetter
+ * @version $Id$
+ */
+public interface GenericOrgaUnitTab {
+
+ boolean hasData(GenericOrganizationalUnit orgaunit);
+
+ void generateXml(GenericOrganizationalUnit orgaunit,
+ Element parent,
+ PageState state);
+
+}
diff --git a/ccm-cms/src/com/arsdigita/cms/contenttypes/ui/GenericOrganizationalUnitPanel.java b/ccm-cms/src/com/arsdigita/cms/contenttypes/ui/GenericOrganizationalUnitPanel.java
index d6132a232..058b6a7ff 100644
--- a/ccm-cms/src/com/arsdigita/cms/contenttypes/ui/GenericOrganizationalUnitPanel.java
+++ b/ccm-cms/src/com/arsdigita/cms/contenttypes/ui/GenericOrganizationalUnitPanel.java
@@ -37,7 +37,10 @@ import org.apache.log4j.Logger;
/**
*
* @author Jens Pelzetter
+ *
+ * @deprecated Replaced with {@link GenericOrgaUnitExtraXmlGenerator}.
*/
+@Deprecated
public class GenericOrganizationalUnitPanel extends CompoundContentItemPanel {
private final static Logger logger =