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 =