From 24db30a69bc1d8821b2211b245c68f9dad109a15 Mon Sep 17 00:00:00 2001 From: jensp Date: Wed, 11 Jan 2017 18:35:23 +0000 Subject: [PATCH] CCM NG: Current progress of the migration of the UI for ccm-cms git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4516 8810af33-2d31-482b-a856-94f89814c4df --- .../cms/ui/ContentItemContextBar.java.todo | 68 +- ...ava => ContentSectionContextBar.java.todo} | 12 +- ...Page.java => ContentSectionPage.java.todo} | 0 .../{ItemSearch.java => ItemSearch.java.todo} | 0 ...ne.java => ItemSearchBrowsePane.java.todo} | 0 ...ava => ItemSearchFlatBrowsePane.java.todo} | 0 ...java => ItemSearchFolderBrowser.java.todo} | 0 ...archPage.java => ItemSearchPage.java.todo} | 0 ...chPopup.java => ItemSearchPopup.java.todo} | 0 ...ction.java => ItemSearchSection.java.todo} | 0 .../arsdigita/cms/ui/WorkspaceContextBar.java | 46 +- .../com/arsdigita/cms/ui/item/Summary.java | 367 ++++++ .../arsdigita/cms/ui/item/Summary.java.todo | 455 -------- .../ItemLifecycleAdminPane.java.todo | 207 ++-- .../lifecycle/ItemLifecycleItemPane.java.todo | 1019 ++++++++++++++++ .../ItemLifecycleSelectForm.java.todo | 1024 +++++++++++++++++ ...Pane.java => LifecycleAdminPane.java.todo} | 0 ...mPane.java => LifecycleItemPane.java.todo} | 0 .../ui/lifecycle/LifecycleRequestLocal.java | 31 + ...emPane.java => BaseRoleItemPane.java.todo} | 0 ...AdminPane.java => RoleAdminPane.java.todo} | 0 ...nent.java => ItemQueryComponent.java.todo} | 0 .../cms/ui/type/ContentTypePropertyList.java | 11 +- .../cms/ui/workflow/BaseWorkflowItemPane.java | 1 + .../cms/ui/workflow/TaskItemPane.java | 1 + .../main/java/org/librecms/CmsConstants.java | 2 + .../com/arsdigita/toolbox/ui/ContextBar.java | 23 +- .../com/arsdigita/toolbox/ui/Property.java | 62 + .../arsdigita/toolbox/ui/PropertyList.java | 70 +- .../AbstractAuditedEntityRepository.java | 41 +- 30 files changed, 2752 insertions(+), 688 deletions(-) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/{ContentSectionContextBar.java => ContentSectionContextBar.java.todo} (94%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/{ContentSectionPage.java => ContentSectionPage.java.todo} (100%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/{ItemSearch.java => ItemSearch.java.todo} (100%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/{ItemSearchBrowsePane.java => ItemSearchBrowsePane.java.todo} (100%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/{ItemSearchFlatBrowsePane.java => ItemSearchFlatBrowsePane.java.todo} (100%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/{ItemSearchFolderBrowser.java => ItemSearchFolderBrowser.java.todo} (100%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/{ItemSearchPage.java => ItemSearchPage.java.todo} (100%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/{ItemSearchPopup.java => ItemSearchPopup.java.todo} (100%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/{ItemSearchSection.java => ItemSearchSection.java.todo} (100%) create mode 100755 ccm-cms/src/main/java/com/arsdigita/cms/ui/item/Summary.java delete mode 100755 ccm-cms/src/main/java/com/arsdigita/cms/ui/item/Summary.java.todo create mode 100755 ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/ItemLifecycleItemPane.java.todo create mode 100755 ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/ItemLifecycleSelectForm.java.todo rename ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/{LifecycleAdminPane.java => LifecycleAdminPane.java.todo} (100%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/{LifecycleItemPane.java => LifecycleItemPane.java.todo} (100%) create mode 100755 ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/LifecycleRequestLocal.java rename ccm-cms/src/main/java/com/arsdigita/cms/ui/role/{BaseRoleItemPane.java => BaseRoleItemPane.java.todo} (100%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/role/{RoleAdminPane.java => RoleAdminPane.java.todo} (100%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/search/{ItemQueryComponent.java => ItemQueryComponent.java.todo} (100%) create mode 100644 ccm-core/src/main/java/com/arsdigita/toolbox/ui/Property.java diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/ContentItemContextBar.java.todo b/ccm-cms/src/main/java/com/arsdigita/cms/ui/ContentItemContextBar.java.todo index 690b6cf8a..3442ff5db 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/ContentItemContextBar.java.todo +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/ContentItemContextBar.java.todo @@ -20,64 +20,59 @@ package com.arsdigita.cms.ui; import com.arsdigita.bebop.PageState; import com.arsdigita.cms.CMS; -import com.arsdigita.cms.ContentItem; -import com.arsdigita.cms.ContentSection; -import com.arsdigita.cms.ContentType; + +import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.ContentSection; +import org.librecms.contentsection.ContentType; + import com.arsdigita.cms.ItemSelectionModel; -import com.arsdigita.cms.Template; import com.arsdigita.cms.PageLocations; import com.arsdigita.web.ParameterMap; import com.arsdigita.web.URL; -import org.apache.log4j.Logger; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.util.List; /** - *

The context bar of the content section UI.

+ *

+ * The context bar of the content section UI.

* - * @author Justin Ross <jross@redhat.com> - * @version $Id: ContentItemContextBar.java 287 2005-02-22 00:29:02Z sskracic $ + * @author Justin Ross + * @author Jens Pelzetter */ class ContentItemContextBar extends ContentSectionContextBar { - private static final Logger s_log = Logger.getLogger - (ContentItemContextBar.class); + private final ItemSelectionModel itemSelectionModel; - private final ItemSelectionModel m_item; - - ContentItemContextBar(final ItemSelectionModel item) { + ContentItemContextBar(final ItemSelectionModel itemSelectionModel) { super(); - m_item = item; + this.itemSelectionModel = itemSelectionModel; } @Override - protected final List entries(final PageState state) { - final List entries = super.entries(state); - final ContentItem item = (ContentItem) m_item.getSelectedObject(state); + protected final List entries(final PageState state) { + final List entries = super.entries(state); + final ContentItem item = itemSelectionModel.getSelectedObject(state); final ContentSection section = CMS.getContext().getContentSection(); - boolean isTemplate = - item.getContentType().equals(ContentType.findByAssociatedObjectType(Template.BASE_DATA_OBJECT_TYPE)); - final URL url = URL.there - (state.getRequest(), - section.getPath() + "/" + PageLocations.ITEM_PAGE, - params(item)); + final URL url = URL.there(state.getRequest(), + section.getPrimaryUrl() + "/" + + PageLocations.ITEM_PAGE, + params(item)); - StringBuffer title = new StringBuffer(); - if (isTemplate) { - title.append(localize("cms.ui.template")); - } else { - title.append(localize("cms.ui.content_item")); - } + final StringBuilder title = new StringBuilder(); + title.append(localize("cms.ui.content_item")); title.append(": ") .append(item.getDisplayName()); - String language = item.getLanguage(); - if (language != null) { - title.append(" (") - .append(language) - .append(")"); - } +// final String language = item.getLanguage(); +// if (language != null) { +// title.append(" (") +// .append(language) +// .append(")"); +// } entries.add(new Entry(title.toString(), url)); @@ -87,7 +82,7 @@ class ContentItemContextBar extends ContentSectionContextBar { private static ParameterMap params(final ContentItem item) { final ParameterMap params = new ParameterMap(); - params.setParameter(ContentItemPage.ITEM_ID, item.getID()); + params.setParameter(ContentItemPage.ITEM_ID, item.getObjectId()); return params; } @@ -95,4 +90,5 @@ class ContentItemContextBar extends ContentSectionContextBar { private static String localize(final String key) { return (String) ContentSectionPage.globalize(key).localize(); } + } diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/ContentSectionContextBar.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/ContentSectionContextBar.java.todo similarity index 94% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/ContentSectionContextBar.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/ContentSectionContextBar.java.todo index 005ad06cc..d1bcc71ef 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/ContentSectionContextBar.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/ContentSectionContextBar.java.todo @@ -24,7 +24,6 @@ import com.arsdigita.cms.PageLocations; import org.librecms.contentsection.ContentItem; import org.librecms.contentsection.ContentSection; -import org.librecms.contentsection.Folder; import com.arsdigita.web.ParameterMap; import com.arsdigita.web.URL; @@ -36,11 +35,6 @@ import java.util.List; import java.util.Stack; import org.apache.logging.log4j.Logger; -import org.libreccm.cdi.utils.CdiUtil; -import org.libreccm.core.CcmObject; -import org.librecms.contentsection.ContentSectionManager; - -import java.util.Optional; /** * The context bar of the content section UI. @@ -54,14 +48,14 @@ public class ContentSectionContextBar extends WorkspaceContextBar { ContentSectionContextBar.class); @Override - protected List entries(final PageState state) { + protected List entries(final PageState state) { /* Include breadcrumb entries already set by content-center (i.e. the * URL of the content center itself */ - final List entries = super.entries(state); + final List entries = super.entries(state); final ContentSection section = CMS.getContext().getContentSection(); - final Stack folderEntryStack = new Stack(); + final Stack folderEntryStack = new Stack<>(); String currentFolderLabel = null; ParameterMap params = new ParameterMap(); boolean isTemplate = false; diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/ContentSectionPage.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/ContentSectionPage.java.todo similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/ContentSectionPage.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/ContentSectionPage.java.todo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearch.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearch.java.todo similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearch.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearch.java.todo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchBrowsePane.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchBrowsePane.java.todo similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchBrowsePane.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchBrowsePane.java.todo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchFlatBrowsePane.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchFlatBrowsePane.java.todo similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchFlatBrowsePane.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchFlatBrowsePane.java.todo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchFolderBrowser.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchFolderBrowser.java.todo similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchFolderBrowser.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchFolderBrowser.java.todo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchPage.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchPage.java.todo similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchPage.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchPage.java.todo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchPopup.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchPopup.java.todo similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchPopup.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchPopup.java.todo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchSection.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchSection.java.todo similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchSection.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchSection.java.todo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/WorkspaceContextBar.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/WorkspaceContextBar.java index 6bed0e95b..e29745f8a 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/WorkspaceContextBar.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/WorkspaceContextBar.java @@ -19,53 +19,57 @@ package com.arsdigita.cms.ui; import com.arsdigita.bebop.PageState; -import com.arsdigita.cms.ContentCenter; import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.toolbox.ui.ContextBar; import com.arsdigita.web.URL; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; 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; import org.librecms.CmsConstants; import java.util.List; -import java.util.Map; /** - *

The context bar of the content center UI.

+ *

+ * The context bar of the content center UI.

* - * @author Justin Ross <jross@redhat.com> - * @version $Id$ + * @author Justin Ross + * @author Jens Pelzetter */ // Made public (instead of unspecified) in 6.6.8 public class WorkspaceContextBar extends ContextBar { - /** A logger instance, primarily to assist debugging . */ - private static final Logger s_log = Logger.getLogger - (WorkspaceContextBar.class); + /** + * A logger instance, primarily to assist debugging . + */ + private static final Logger LOGGER = LogManager.getLogger( + WorkspaceContextBar.class); /** - * + * * @param state - * @return + * + * @return */ @Override - protected List entries(final PageState state) { + protected List entries(final PageState state) { - final List entries = super.entries(state); + final List entries = super.entries(state); - final String centerTitle = (String) new GlobalizedMessage("cms.ui.content_center", CmsConstants.CMS_BUNDLE).localize(); + final String centerTitle = (String) new GlobalizedMessage( + "cms.ui.content_center", CmsConstants.CMS_BUNDLE).localize(); final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); - final ApplicationRepository appRepo = cdiUtil.findBean(ApplicationRepository.class); - final List apps = appRepo.findByType(CmsConstants.CONTENT_SECTION_APP_TYPE); - + final ApplicationRepository appRepo = cdiUtil.findBean( + ApplicationRepository.class); + final List apps = appRepo.findByType( + CmsConstants.CONTENT_SECTION_APP_TYPE); + final String centerPath = apps.get(0).getPrimaryUrl(); - if (s_log.isDebugEnabled()) { - s_log.debug("Got Url: " + centerPath); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Got Url: " + centerPath); } final URL url = URL.there(state.getRequest(), centerPath); diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/Summary.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/Summary.java new file mode 100755 index 000000000..c504b3dbc --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/Summary.java @@ -0,0 +1,367 @@ +/* + * 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.cms.ui.item; + +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; + +import com.arsdigita.bebop.PageState; + +import org.libreccm.categorization.Category; + +import com.arsdigita.cms.CMS; + +import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.ContentSection; + +import com.arsdigita.cms.ItemSelectionModel; +import com.arsdigita.cms.dispatcher.CMSDispatcher; +import com.arsdigita.cms.dispatcher.ItemResolver; + +import org.librecms.lifecycle.Lifecycle; + +import com.arsdigita.cms.ui.CMSContainer; + +import org.libreccm.security.User; + +import com.arsdigita.toolbox.ui.FormatStandards; +import com.arsdigita.util.Assert; +import com.arsdigita.util.GraphSet; +import com.arsdigita.util.Graphs; +import com.arsdigita.util.UncheckedWrapperException; +import com.arsdigita.web.Web; + +import org.libreccm.workflow.Task; +import org.libreccm.workflow.TaskComment; +import org.libreccm.workflow.Workflow; + +import com.arsdigita.xml.Element; + +import org.libreccm.auditing.CcmRevision; +import org.libreccm.categorization.CategoryManager; +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.l10n.GlobalizationHelper; +import org.libreccm.security.Shiro; +import org.librecms.contentsection.ContentItemRepository; +import org.librecms.contentsection.ContentSectionManager; + +import java.io.UnsupportedEncodingException; +import java.util.Date; +import java.util.Locale; +import java.util.stream.Collectors; + +/** + * This panel displays basic details about a content item such as attributes and + * associations. + * + * Container: {@link com.arsdigita.cms.ui.ContentItemPage} + * + * This panel uses an {@link com.arsdigita.cms.dispatcher.XMLGenerator} to + * convert content items into XML. + * + * @author Michael Pih + * @author Jens Pelzetter + */ +public class Summary extends CMSContainer { + + private static final String SUMMARY = "itemAdminSummary"; + private static final String RESTART_WORKFLOW = "restartWorkflow"; + + private final ItemSelectionModel itemSelectionModel; + + public Summary(final ItemSelectionModel itemSelectionModel) { + super(); + + this.itemSelectionModel = itemSelectionModel; + } + + /** + * Generate XML representation of an item summary. + * + * @param state The page state + * @param parent The parent DOM element + * + * @pre ( state != null ) + * @pre ( parent != null ) + */ + @Override + public void generateXML(PageState state, Element parent) { + if (isVisible(state)) { + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final GlobalizationHelper globalizationHelper = cdiUtil.findBean( + GlobalizationHelper.class); + final Locale language = globalizationHelper.getNegotiatedLocale(); + + // Determine the item's environment + final ContentItem item = getContentItem(state); + final ContentSection section = getContentSection(state); + + final Shiro shiro = cdiUtil.findBean(Shiro.class); + final User user = shiro.getUser(); + + // Setup xml element for item's properties + final Element itemElement = new Element("cms:itemSummary", + CMS.CMS_XML_NS); + + // Determine item's name / url stub + itemElement.addAttribute("name", item.getDisplayName()); + + // obviously getName() here gets the 'semantically meaningful name' + // from database using class DataType. It is not localizable! And + // it is not really 'semantically meaningful' + final String objectType = item.getClass().getName(); + + // Quasimodo: ObjectType for summary + itemElement.addAttribute("objectType", objectType); + itemElement.addAttribute("description", + item.getDescription().getValue(language)); + + itemElement.addAttribute("title", + item.getTitle().getValue(language)); + + // subject category + final Element subjectCategoriesElement = new Element( + "cms:subjectCategories", CMS.CMS_XML_NS); + itemElement.addContent(subjectCategoriesElement); + + // URL + final Element linkElement = new Element("cms:linkSummary", + CMS.CMS_XML_NS); + try { + linkElement.addAttribute( + "url", + String.format("%s/redirect?oid=%s", + Web.getWebappContextPath(), + URLEncoder.encode(item.getUuid(), "UTF-8"))); + } catch (UnsupportedEncodingException ex) { + throw new UncheckedWrapperException(ex); + } + + //"/redirect?oid=" + URLEncoder.encode(item.getDraftVersion().getOID().toString())); + // WORKFLOW + final Element workflowElement = new Element("cms:workflowSummary", + CMS.CMS_XML_NS); + final Workflow workflow = item.getWorkflow(); + if (workflow == null) { + workflowElement.addAttribute("noWorkflow", "1"); + } else { + workflowElement.addAttribute("name", + workflow.getName().getValue( + language)); + + final List tasks = workflow.getTasks(); + final GraphSet graph = new GraphSet(); + + for (final Task task : tasks) { + final List dependsOn = task.getDependsOn(); + final StringBuilder builder = new StringBuilder(); + for (final Task dep : dependsOn) { + graph.addEdge(task, dep, null); + builder.append(dep.getLabel().getValue(language)); + } + + final int len = builder.length(); + if (len >= 2) { + builder.setLength(len - 2); + } else { + graph.addNode(task); + } + } + + final List taskList = new ArrayList<>(); + outer: + while (graph.nodeCount() > 0) { + @SuppressWarnings("unchecked") + final List list = Graphs.getSinkNodes(graph); + for (final Task task : list) { + taskList.add(0, task); + graph.removeNode(task); + continue outer; + } + // break loop if no nodes removed + break; + } + + for (final Task task : taskList) { + Element taskElement = new Element("cms:task", + CMS.CMS_XML_NS); + taskElement.addAttribute("name", + task.getLabel().getValue(language)); + taskElement.addAttribute("state", + task.getTaskState().toString()); + for (final TaskComment comment : task.getComments()) { + final Element commentElement = new Element( + "cms:taskComment", CMS.CMS_XML_NS); + final User author = comment.getAuthor(); + final String authorName; + if (author == null) { + authorName = "Anonymous"; + } else { + authorName = author.getName(); + } + + commentElement.addAttribute("author", authorName); + commentElement.addAttribute("comment", + comment.getComment()); + taskElement.addContent(commentElement); + } + + workflowElement.addContent(taskElement); + } + } + + // Revision History (we are using to "transaction" for XML elememts + // here because this used by the old API and we don't want to brake + // the XSL. + final Element revisionsElement = new Element( + "cms:transactionSummary", + CMS.CMS_XML_NS); + final ContentItemRepository itemRepo = cdiUtil.findBean( + ContentItemRepository.class); + final List revisions = itemRepo.retrieveRevisions( + item, item.getObjectId()); + if (revisions != null && !revisions.isEmpty()) { + revisionsElement.addAttribute( + "creationDate", + FormatStandards.formatDate(revisions.get(0) + .getRevisionDate())); + revisionsElement.addAttribute( + "lastModifiedDate", + FormatStandards + .formatDate(revisions.get(revisions.size() - 1) + .getRevisionDate())); + final ContentSectionManager sectionManager = cdiUtil.findBean( + ContentSectionManager.class); + final ItemResolver itemResolver = sectionManager + .getItemResolver(section); + for (final CcmRevision revision : revisions) { + final Element revisionElement = new Element( + "cms:transaction", CMS.CMS_XML_NS); + revisionElement.addAttribute( + "date", + FormatStandards.formatDate(revision.getRevisionDate())); + final String authorName; + if (revision.getUserName() == null + || revision.getUserName().trim().isEmpty()) { + authorName = "Anonymous"; + } else { + authorName = revision.getUserName(); + } + revisionElement.addAttribute("author", authorName); + + final String url = String.format( + "%s?revision=%d", + itemResolver.generateItemURL( + state, + item, + section, + CMSDispatcher.PREVIEW), + revision.getId()); + revisionElement.addAttribute("url", url); + revisionsElement.addContent(revisionElement); + } + } + + // CATEGORY + final Element categoriesElement = new Element( + "cms:categorySummary", CMS.CMS_XML_NS); + + final List categories = item.getCategories().stream() + .map(categorization -> categorization.getCategory()) + .collect(Collectors.toList()); + final CategoryManager categoryManager = cdiUtil.findBean( + CategoryManager.class); + for (final Category category : categories) { + final Element categoryElement = new Element("cms:category", + CMS.CMS_XML_NS); + categoryElement.setText(categoryManager + .getCategoryPath(category)); + categoriesElement.addContent(categoryElement); + } + + // LIFECYCLE + final Element lifecycleElement = new Element("cms:lifecycleSummary", + CMS.CMS_XML_NS); + + final Lifecycle lifecycle = item.getLifecycle(); + if (lifecycle == null) { + lifecycleElement.addAttribute("noLifecycle", "1"); + } else { + lifecycleElement.addAttribute( + "name", + lifecycle.getDefinition().getLabel().getValue(language)); + lifecycleElement.addAttribute( + "startDate", + FormatStandards.formatDate(lifecycle.getStartDateTime())); + + final Date endDate = lifecycle.getEndDateTime(); + if (endDate == null) { + lifecycleElement.addAttribute("endDateString", + "last forever"); + } else { + lifecycleElement.addAttribute( + "endDateString", + String.format("expire on %s", + FormatStandards.formatDate(endDate))); + lifecycleElement.addAttribute( + "endDate", FormatStandards.formatDate(endDate)); + } + + lifecycleElement.addAttribute( + "hasBegun", Boolean.toString(lifecycle.isStarted())); + lifecycleElement.addAttribute( + "hasEnded", Boolean.toString(lifecycle.isFinished())); + } + + parent.addContent(itemElement); + parent.addContent(categoriesElement); + parent.addContent(linkElement); + parent.addContent(lifecycleElement); + parent.addContent(workflowElement); + parent.addContent(revisionsElement); + } + } + + /** + * Fetch the selected content item. + * + * @param state The page state + * + * @return The selected item + */ + protected ContentItem getContentItem(final PageState state) { + final ContentItem item = itemSelectionModel.getSelectedObject(state); + Assert.exists(item); + return item; + } + + /** + * Fetch the current content section. + * + * @param state The page state + * + * @return The content section + */ + protected ContentSection getContentSection(final PageState state) { + return CMS.getContext().getContentSection(); + } + +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/Summary.java.todo b/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/Summary.java.todo deleted file mode 100755 index 85ee3b2ab..000000000 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/Summary.java.todo +++ /dev/null @@ -1,455 +0,0 @@ -/* - * 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.cms.ui.item; - -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import javax.servlet.ServletException; - -import com.arsdigita.bebop.PageState; -import com.arsdigita.categorization.Category; -import com.arsdigita.categorization.CategoryCollection; -import com.arsdigita.cms.CMS; -import com.arsdigita.cms.ContentItem; -import com.arsdigita.cms.ContentPage; -import com.arsdigita.cms.ContentSection; -import com.arsdigita.cms.ItemSelectionModel; -import com.arsdigita.cms.SecurityManager; -import com.arsdigita.cms.dispatcher.CMSDispatcher; -import com.arsdigita.cms.lifecycle.Lifecycle; -import com.arsdigita.cms.ui.CMSContainer; -import com.arsdigita.cms.util.SecurityConstants; -import com.arsdigita.cms.workflow.CMSEngine; -import com.arsdigita.cms.workflow.CMSTask; -import com.arsdigita.domain.DataObjectNotFoundException; -import com.arsdigita.domain.DomainServiceInterfaceExposer; -import com.arsdigita.kernel.ACSObject; -import com.arsdigita.kernel.User; -import com.arsdigita.kernel.permissions.PermissionDescriptor; -import com.arsdigita.kernel.permissions.PermissionService; -import com.arsdigita.kernel.permissions.PrivilegeDescriptor; -import com.arsdigita.persistence.Filter; -import com.arsdigita.toolbox.ui.FormatStandards; -import com.arsdigita.util.Assert; -import com.arsdigita.util.GraphSet; -import com.arsdigita.util.Graphs; -import com.arsdigita.util.UncheckedWrapperException; -import com.arsdigita.versioning.Transaction; -import com.arsdigita.versioning.TransactionCollection; -import com.arsdigita.versioning.Versions; -import com.arsdigita.web.RedirectSignal; -import com.arsdigita.web.Web; -import com.arsdigita.web.WebContext; -import com.arsdigita.workflow.simple.Engine; -import com.arsdigita.workflow.simple.Task; -import com.arsdigita.workflow.simple.TaskCollection; -import com.arsdigita.workflow.simple.TaskComment; -import com.arsdigita.workflow.simple.Workflow; -import com.arsdigita.workflow.simple.WorkflowTemplate; -import com.arsdigita.xml.Element; -import java.io.UnsupportedEncodingException; - -/** - *

- * This panel displays basic details about a content item such as attributes and associations.

- * - *

- * Container: {@link com.arsdigita.cms.ui.ContentItemPage} - * - *

- * This panel uses an {@link com.arsdigita.cms.dispatcher.XMLGenerator} to convert content items - * into XML.

- * - * @author Michael Pih (pihman@arsdigita.com) - * @version $Id: Summary.java 1940 2009-05-29 07:15:05Z terry $ - */ -public class Summary extends CMSContainer { - - private static final String SUMMARY = "itemAdminSummary"; - private static final String RESTART_WORKFLOW = "restartWorkflow"; - - private final ItemSelectionModel m_item; - - public Summary(ItemSelectionModel m) { - super(); - - m_item = m; - } - - /** - * Generate XML representation of an item summary. - * - * @param state The page state - * @param parent The parent DOM element - * - * @pre ( state != null ) - * @pre ( parent != null ) - */ - @Override - public void generateXML(PageState state, Element parent) { - if (isVisible(state)) { - - // Determine the item's environment - ContentItem item = getContentItem(state); - ContentSection section = getContentSection(state); - User user = Web.getWebContext().getUser(); - - // Setup xml element for item's properties - Element itemElement = new Element("cms:itemSummary", CMS.CMS_XML_NS); - - // Determine item's name / url stub - itemElement.addAttribute("name", item.getName()); - - // obviously getName() here gets the 'semantically meaningful name' - // from database using class DataType. It is not localizable! And - // it is not really 'semantically meaningful' - String objectType = item.getObjectType().getName(); - - // Quasimodo: ObjectType for summary - itemElement.addAttribute("objectType", objectType); - - // NOT USED - CUSTOMIZED SUMMARY - // Take advantage of caching in the CMS Dispatcher. - // XMLGenerator xmlGenerator = section.getXMLGenerator(); - // xmlGenerator.generateXML(state, parent, SUMMARY); - String descriptionAttribute = ""; - if (objectType.equals("NewsItem") || objectType.equals("Article")) { - descriptionAttribute = "lead"; - } else if (objectType.equals("FileStorageItem") || objectType.equals("Minutes")) { - descriptionAttribute = "description"; - } else if (objectType.equals("Job")) { - descriptionAttribute = "jobDescription"; - } else if (objectType.equals("MultiPartArticle") || objectType.equals("Agenda") - || objectType.equals("PressRelease") || objectType.equals("Service")) { - descriptionAttribute = "summary"; - } - - if (!descriptionAttribute.equals("")) { - itemElement.addAttribute("description", (String) DomainServiceInterfaceExposer.get( - item, descriptionAttribute)); - } - - try { - ContentPage page = new ContentPage(item.getID()); - itemElement.addAttribute("title", page.getTitle()); - } catch (DataObjectNotFoundException ex) { - // - } - - // subject category - Element subjectsElement = new Element("cms:subjectCategories", CMS.CMS_XML_NS); - itemElement.addContent(subjectsElement); - Category itemCategory = null; - Category subjectCategory = Category.getRootForObject(section, "subject"); - if (subjectCategory != null) { - CategoryCollection categories = item.getCategoryCollection(); - while (categories.next()) { - Category category = categories.getCategory(); - CategoryCollection parents = category.getDefaultAscendants(); - parents.addOrder(Category.DEFAULT_ANCESTORS); - if (parents.next()) { - Category parentCategory = parents.getCategory(); - if (parentCategory.equals(subjectCategory)) { - Element subjectElement = new Element("cms:subjectCategory", - CMS.CMS_XML_NS); - subjectElement.addAttribute("name", category.getName()); - subjectElement.setText(category.getPreferredQualifiedName(" -> ", - true)); - subjectsElement.addContent(subjectElement); - } - parents.close(); - } - } - } - - // URL - Element linkElement = new Element("cms:linkSummary", CMS.CMS_XML_NS); - try { - linkElement.addAttribute("url", - String.format("%s/redirect?oid=%s", - Web.getWebappContextPath(), - URLEncoder.encode(item.getDraftVersion() - .getOID() - .toString(), "utf-8"))); - } catch (UnsupportedEncodingException ex) { - throw new UncheckedWrapperException(ex); - } - - //"/redirect?oid=" + URLEncoder.encode(item.getDraftVersion().getOID().toString())); - // WORKFLOW - Element workflowElement = new Element("cms:workflowSummary", CMS.CMS_XML_NS); - Workflow workflow = Workflow.getObjectWorkflow(item); - - SecurityManager sm = CMS.getContext().getSecurityManager(); - if (canWorkflowBeExtended(user, item, workflow)) { - // control event for restarting workflow in edit mode - try { - state.setControlEvent(this, RESTART_WORKFLOW, item.getID().toString()); - workflowElement.addAttribute("restartWorkflowURL", state.stateAsURL()); - state.clearControlEvent(); - } catch (java.io.IOException ex) { - // - } - } - - if (workflow == null) { - workflowElement.addAttribute("noWorkflow", "1"); - } else { - workflowElement.addAttribute("name", workflow.getDisplayName()); - - TaskCollection tc = workflow.getTaskCollection(); - GraphSet g = new GraphSet(); - while (tc.next()) { - Task t = tc.getTask(); - final TaskCollection deps = t.getRequiredTasks(); - final StringBuffer buffer = new StringBuffer(); - while (deps.next()) { - Task dep = deps.getTask(); - g.addEdge(t, dep, null); - buffer.append(dep.getLabel() + ", "); - } - - final int len = buffer.length(); - if (len >= 2) { - buffer.setLength(len - 2); - } else { - g.addNode(t); - } - deps.close(); - } - - List taskList = new ArrayList(); - outer: - while (g.nodeCount() > 0) { - List l = Graphs.getSinkNodes(g); - for (Iterator it = l.iterator(); it.hasNext();) { - Task t = (Task) it.next(); - taskList.add(0, t); - g.removeNode(t); - continue outer; - } - // break loop if no nodes removed - break; - } - Iterator tasks = taskList.iterator(); - - while (tasks.hasNext()) { - Task task = (Task) tasks.next(); - Element taskElement = new Element("cms:task", CMS.CMS_XML_NS); - taskElement.addAttribute("name", task.getDisplayName()); - taskElement.addAttribute("state", task.getStateString()); - Iterator comments = task.getComments(); - while (comments.hasNext()) { - TaskComment comment = (TaskComment) comments.next(); - Element commentElement = new Element("cms:taskComment", CMS.CMS_XML_NS); - User author = comment.getUser(); - String authorName = "Anonymous"; - if (author != null) { - authorName = author.getDisplayName(); - } - - commentElement.addAttribute("author", authorName); - commentElement.addAttribute("comment", comment.getComment()); - commentElement.addAttribute("date", FormatStandards.formatDate(comment - .getDate())); - - taskElement.addContent(commentElement); - } - - workflowElement.addContent(taskElement); - } - } - - // REVISION HISTORY - Element transactionElement = new Element("cms:transactionSummary", CMS.CMS_XML_NS); - transactionElement.addAttribute("creationDate", FormatStandards.formatDate(item - .getCreationDate())); - transactionElement.addAttribute("lastModifiedDate", FormatStandards.formatDate(item - .getLastModifiedDate())); - - TransactionCollection transactions = Versions.getTaggedTransactions(item.getOID()); - while (transactions.next()) { - Transaction transaction = transactions.getTransaction(); - Element element = new Element("cms:transaction", CMS.CMS_XML_NS); - element.addAttribute("date", FormatStandards.formatDate(transaction.getTimestamp())); - String authorName = "Anonymous"; - User author = transaction.getUser(); - if (author != null) { - authorName = author.getDisplayName(); - } - element.addAttribute("author", authorName); - - String url = section.getItemResolver().generateItemURL(state, item, section, - CMSDispatcher.PREVIEW) - + "?transID=" + transaction.getID(); - element.addAttribute("url", url); - transactionElement.addContent(element); - } - - transactions.close(); - - // CATEGORY - Element categoryElement = new Element("cms:categorySummary", CMS.CMS_XML_NS); - - CategoryCollection categories = item.getCategoryCollection(); - while (categories.next()) { - Category category = categories.getCategory(); - Element element = new Element("cms:category", CMS.CMS_XML_NS); - element.setText(category.getPreferredQualifiedName(" -> ", true)); - categoryElement.addContent(element); - - } - categories.close(); - - // LIFECYCLE - Element lifecycleElement = new Element("cms:lifecycleSummary", CMS.CMS_XML_NS); - - Lifecycle lifecycle = item.getLifecycle(); - if (lifecycle == null) { - lifecycleElement.addAttribute("noLifecycle", "1"); - } else { - lifecycleElement.addAttribute("name", lifecycle.getLabel()); - lifecycleElement.addAttribute("startDate", FormatStandards.formatDate(lifecycle - .getStartDate())); - - java.util.Date endDate = lifecycle.getEndDate(); - if (endDate == null) { - lifecycleElement.addAttribute("endDateString", "last forever"); - } else { - lifecycleElement.addAttribute("endDateString", "expire on " + FormatStandards - .formatDate(endDate)); - lifecycleElement.addAttribute("endDate", FormatStandards.formatDate(endDate)); - } - - lifecycleElement.addAttribute("hasBegun", (new Boolean(lifecycle.hasBegun())) - .toString()); - lifecycleElement.addAttribute("hasEnded", (new Boolean(lifecycle.hasEnded())) - .toString()); - } - - parent.addContent(itemElement); - parent.addContent(categoryElement); - parent.addContent(linkElement); - parent.addContent(lifecycleElement); - parent.addContent(workflowElement); - parent.addContent(transactionElement); - } - } - - /** - * Fetch the selected content item. - * - * @param state The page state - * - * @return The selected item - * - * @pre ( state != null ) - */ - protected ContentItem getContentItem(PageState state) { - ContentItem item = (ContentItem) m_item.getSelectedObject(state); - Assert.exists(item); - return item; - } - - /** - * Fetch the current content section. - * - * @param state The page state - * - * @return The content section - * - * @pre ( state != null ) - */ - protected ContentSection getContentSection(PageState state) { - ContentSection section = CMS.getContext().getContentSection(); - return section; - } - - public void respond(PageState state) throws ServletException { - String key = state.getControlEventName(); - String value = state.getControlEventValue(); - if (RESTART_WORKFLOW.equals(key)) { - User user = Web.getWebContext().getUser(); - ContentItem item = getContentItem(state); - ContentSection section = item.getContentSection(); - Workflow w = Workflow.getObjectWorkflow(item); - - if (canWorkflowBeExtended(user, item, w)) { - WorkflowTemplate template = w.getWorkflowTemplate(); - if (template != null) { - template.extendWorkflow(w); - w.save(); - } - - // lock the next task - Engine engine = Engine.getInstance(CMSEngine.CMS_ENGINE_TYPE); - Iterator i = engine.getEnabledTasks(user, w.getID()).iterator(); - if (i.hasNext()) { - CMSTask task = (CMSTask) i.next(); - - if (!task.isLocked()) { - task.lock(user); - } - } - } - - String redirectURL = Web.getConfig().getDispatcherServletPath() + item - .getContentSection().getPath() + "/admin/item.jsp?item_id=" + item.getID() - + "&set_tab=1"; - throw new RedirectSignal(redirectURL, true); - } else { - throw new ServletException("Unknown control event: " + key); - } - } - - /* - * Checks if workflow can be extended - */ - protected boolean canWorkflowBeExtended(User user, ContentItem item, Workflow workflow) { - boolean canBeExtended = true; - - if (workflow == null) { - canBeExtended = false; - } else if (!workflow.isFinished()) { - canBeExtended = false; - } else if (workflow.getWorkflowTemplate() == null) { - canBeExtended = false; - } else { - TaskCollection templates = item.getContentSection().getWorkflowTemplates(); - Filter f = templates.addInSubqueryFilter("id", - "com.arsdigita.cms.getWorkflowTemplateUserFilter"); - f.set("userId", Web.getWebContext().getUser().getID()); - templates.addEqualsFilter(ACSObject.ID, workflow.getWorkflowTemplate().getID()); - - PrivilegeDescriptor pd = PrivilegeDescriptor.get(SecurityConstants.CMS_WORKFLOW_ADMIN); - PermissionDescriptor perm = new PermissionDescriptor(pd, item, user); - if (!(templates.next() || PermissionService.checkPermission(perm))) { - canBeExtended = false; - } - templates.close(); - - } - - return canBeExtended; - } - -} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/ItemLifecycleAdminPane.java.todo b/ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/ItemLifecycleAdminPane.java.todo index 1aacd1861..df604589c 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/ItemLifecycleAdminPane.java.todo +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/ItemLifecycleAdminPane.java.todo @@ -24,12 +24,10 @@ import com.arsdigita.bebop.Page; import com.arsdigita.bebop.PageState; import com.arsdigita.bebop.event.ActionEvent; import com.arsdigita.bebop.event.ActionListener; -import com.arsdigita.categorization.Category; -import com.arsdigita.categorization.CategoryCollection; -import com.arsdigita.cms.CMS; -import com.arsdigita.cms.CMSConfig; -import com.arsdigita.cms.ContentItem; -import com.arsdigita.cms.lifecycle.Lifecycle; + +import org.librecms.contentsection.ContentItem; +import org.librecms.lifecycle.Lifecycle; + import com.arsdigita.cms.ui.BaseItemPane; import com.arsdigita.cms.ui.ContentItemPage; import com.arsdigita.cms.ui.item.ContentItemRequestLocal; @@ -37,101 +35,110 @@ import com.arsdigita.toolbox.ui.LayoutPanel; import com.arsdigita.web.RedirectSignal; import com.arsdigita.web.URL; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.security.PermissionChecker; +import org.librecms.contentsection.privileges.ItemPrivileges; + /** * @author Michael Pih * @author Jack Chung * @author Justin Ross <jross@redhat.com> - * @author Jens Pelzetter jens@jp-digital.de - * @version $Id: ItemLifecycleAdminPane.java 1942 2009-05-29 07:53:23Z terry $ + * @author Jens Pelzetter */ public class ItemLifecycleAdminPane extends BaseItemPane { - private static final Logger s_log = Logger.getLogger( - ItemLifecycleAdminPane.class); - private final ContentItemRequestLocal m_item; - private final LifecycleRequestLocal m_lifecycle; - private final LayoutPanel m_introPane; - private final LayoutPanel m_detailPane; - private final LayoutPanel m_selectPane; - private final LayoutPanel m_lockedPane; - private final LayoutPanel m_errorPane; - private final LayoutPanel m_cantPublishPane; + private static final Logger LOGGER = LogManager.getLogger( + ItemLifecycleAdminPane.class); + private final ContentItemRequestLocal selectedItem; + private final LifecycleRequestLocal selectedLifecycle; + private final LayoutPanel introPane; + private final LayoutPanel detailPane; + private final LayoutPanel selectPane; + private final LayoutPanel lockedPane; + private final LayoutPanel errorPane; + private final LayoutPanel cantPublishPane; - public ItemLifecycleAdminPane(final ContentItemRequestLocal item) { - m_item = item; - m_lifecycle = new ItemLifecycleRequestLocal(); + public ItemLifecycleAdminPane(final ContentItemRequestLocal selectedItem) { + this.selectedItem = selectedItem; + selectedLifecycle = new ItemLifecycleRequestLocal(); - m_introPane = new LayoutPanel(); - add(m_introPane); + introPane = new LayoutPanel(); + add(introPane); final Label message = new Label(gz("cms.ui.item.lifecycle.intro")); - m_introPane.setBody(message); + introPane.setBody(message); - m_detailPane = new LayoutPanel(); - add(m_detailPane); + detailPane = new LayoutPanel(); + add(detailPane); - final ItemLifecycleItemPane itemPane = - new ItemLifecycleItemPane(m_item, - m_lifecycle); - m_detailPane.setBody(itemPane); + final ItemLifecycleItemPane itemPane = new ItemLifecycleItemPane( + selectedItem, selectedLifecycle); + detailPane.setBody(itemPane); - m_selectPane = new LayoutPanel(); - add(m_selectPane); + selectPane = new LayoutPanel(); + add(selectPane); - final ItemLifecycleSelectForm selectForm = - new ItemLifecycleSelectForm(m_item); - m_selectPane.setBody(selectForm); + final ItemLifecycleSelectForm selectForm = new ItemLifecycleSelectForm( + selectedItem); + selectPane.setBody(selectForm); - m_lockedPane = new LayoutPanel(); - add(m_lockedPane); + lockedPane = new LayoutPanel(); + add(lockedPane); final Label lockedMsg = new Label(gz( - "cms.ui.item.lifecycle.publish_locked")); - m_lockedPane.setBody(lockedMsg); + "cms.ui.item.lifecycle.publish_locked")); + lockedPane.setBody(lockedMsg); final ControlLink lockedUpdateLink = new ControlLink(new Label(gz( - "cms.ui.item.lifecycle.publish_locked.update"))); + "cms.ui.item.lifecycle.publish_locked.update"))); lockedUpdateLink.addActionListener(new ActionListener() { + @Override public void actionPerformed(final ActionEvent event) { throw new RedirectSignal( - URL.getDispatcherPath() + URL.getDispatcherPath() + ContentItemPage.getItemURL( - item.getContentItem(event.getPageState()), + selectedItem.getContentItem(event.getPageState()), ContentItemPage.PUBLISHING_TAB), - true); + true); } - }); - m_lockedPane.setBottom(lockedUpdateLink); - m_errorPane = new LayoutPanel(); - add(m_errorPane); + }); + lockedPane.setBottom(lockedUpdateLink); + + errorPane = new LayoutPanel(); + add(errorPane); final Label errorMsg = new Label(gz("cms.ui.lifecycle.publish.error")); - m_errorPane.setBody(errorMsg); - - m_cantPublishPane = new LayoutPanel(); - add(m_cantPublishPane); - - final Label cantPublish = new Label(gz("cms.ui.lifecycle.publish.not_possible_abstract_category")); - m_cantPublishPane.setBody(cantPublish); + errorPane.setBody(errorMsg); - connect(selectForm, m_detailPane); + cantPublishPane = new LayoutPanel(); + add(cantPublishPane); + + final Label cantPublish = new Label(gz( + "cms.ui.lifecycle.publish.not_possible_abstract_category")); + cantPublishPane.setBody(cantPublish); + + connect(selectForm, detailPane); } private class ItemLifecycleRequestLocal extends LifecycleRequestLocal { + @Override protected final Object initialValue(final PageState state) { - final ContentItem item = m_item.getContentItem(state); + final ContentItem item = selectedItem.getContentItem(state); final Lifecycle lifecycle = item.getLifecycle(); - s_log.debug("Returning lifecycle " + lifecycle); + LOGGER.debug("Returning lifecycle " + lifecycle); return lifecycle; } + } + @Override public final void register(final Page page) { super.register(page); @@ -140,71 +147,71 @@ public class ItemLifecycleAdminPane extends BaseItemPane { private class VisibilityListener implements ActionListener { - public final void actionPerformed(final ActionEvent e) { - s_log.debug("Determining which pane to show"); + @Override + public final void actionPerformed(final ActionEvent event) { + LOGGER.debug("Determining which pane to show"); - final PageState state = e.getPageState(); + final PageState state = event.getPageState(); - if (CMSConfig.getInstanceOf().getThreadedPublishing() - && PublishLock.getInstance().isLocked(m_item.getContentItem( - state))) { - if (PublishLock.getInstance().hasError(m_item.getContentItem( - state))) { - push(state, m_errorPane); - } else { - push(state, m_lockedPane); - state.getResponse().addIntHeader("Refresh", 5); - } - } else if(isAssignedToAbstractCategory(m_item.getContentItem(state))) { - push(state, m_cantPublishPane); +// if (CMSConfig.getConfig().isThreadPublishing() +// && PublishLock.getInstance().isLocked(m_item.getContentItem( +// state))) { +// if (PublishLock.getInstance().hasError(m_item.getContentItem( +// state))) { +// push(state, m_errorPane); +// } else { +// push(state, m_lockedPane); +// state.getResponse().addIntHeader("Refresh", 5); +// } +// } else + if (isAssignedToAbstractCategory(selectedItem.getContentItem(state))) { + push(state, cantPublishPane); } else { if (state.isVisibleOnPage(ItemLifecycleAdminPane.this)) { - if (m_lifecycle.getLifecycle(state) == null) { + if (selectedLifecycle.getLifecycle(state) == null) { if (hasPermission(state)) { - push(state, m_selectPane); + push(state, selectPane); } else { - push(state, m_introPane); + push(state, introPane); } } else { - push(state, m_detailPane); + push(state, detailPane); } } } } + } private boolean hasPermission(final PageState state) { - final ContentItem item = m_item.getContentItem(state); + final ContentItem item = selectedItem.getContentItem(state); - return CMS.getContext().getSecurityManager().canAccess( - state.getRequest(), SCHEDULE_PUBLICATION, item); + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final PermissionChecker permissionChecker = cdiUtil.findBean( + PermissionChecker.class); + + return permissionChecker.isPermitted(ItemPrivileges.PUBLISH, item); } - + /** * Checks if the item is assigned to an abstract category. - * + * * A category is abstract if not items can assigned to it. - * + * * @param item - * @return {@code true} if assigned to a abstract category, {@code false} if not. + * + * @return {@code true} if assigned to a abstract category, {@code false} if + * not. */ private boolean isAssignedToAbstractCategory(final ContentItem item) { + + final long count = item.getCategories().stream() + .filter(categorization -> { + return categorization.getCategory().isAbstractCategory(); + }) + .count(); - final CategoryCollection categories = item.getCategoryCollection(); - - boolean result = false; - Category category; - while(categories.next()) { - category = categories.getCategory(); - - if (category.isAbstract()) { - result = true; - break; - } - } - - categories.close(); - - return result; + return count > 0; } + } diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/ItemLifecycleItemPane.java.todo b/ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/ItemLifecycleItemPane.java.todo new file mode 100755 index 000000000..d138ecda6 --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/ItemLifecycleItemPane.java.todo @@ -0,0 +1,1019 @@ +/* + * Copyright (C) 2003-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.cms.ui.lifecycle; + +import com.arsdigita.bebop.ActionLink; +import com.arsdigita.bebop.BoxPanel; +import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.Form; +import com.arsdigita.bebop.FormData; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.RequestLocal; +import com.arsdigita.bebop.SimpleContainer; +import com.arsdigita.bebop.Table; +import com.arsdigita.bebop.event.ActionEvent; +import com.arsdigita.bebop.event.ActionListener; +import com.arsdigita.bebop.event.FormInitListener; +import com.arsdigita.bebop.event.FormProcessListener; +import com.arsdigita.bebop.event.FormSectionEvent; +import com.arsdigita.bebop.event.PrintEvent; +import com.arsdigita.bebop.event.PrintListener; +import com.arsdigita.bebop.form.Option; +import com.arsdigita.bebop.form.SingleSelect; +import com.arsdigita.bebop.form.Submit; +import com.arsdigita.cms.CMS; +import com.arsdigita.cms.ContentCenter; +import com.arsdigita.cms.dispatcher.Utilities; +import com.arsdigita.cms.ui.BaseItemPane; +import com.arsdigita.cms.ui.ContentItemPage; +import com.arsdigita.cms.ui.item.ContentItemRequestLocal; +import com.arsdigita.globalization.GlobalizedMessage; +import com.arsdigita.toolbox.ui.ActionGroup; +import com.arsdigita.toolbox.ui.Property; +import com.arsdigita.toolbox.ui.PropertyList; +import com.arsdigita.toolbox.ui.Section; +import com.arsdigita.util.UncheckedWrapperException; +import com.arsdigita.web.RedirectSignal; +import com.arsdigita.web.URL; +import com.arsdigita.web.Web; +import com.arsdigita.xml.Element; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.arsdigita.cms.CMSConfig; +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.l10n.GlobalizationHelper; +import org.libreccm.notification.Notification; +import org.libreccm.security.Party; +import org.libreccm.security.PermissionChecker; +import org.libreccm.security.User; +import org.libreccm.workflow.Workflow; +import org.libreccm.workflow.WorkflowManager; +import org.librecms.CmsConstants; +import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.ContentItemManager; +import org.librecms.contentsection.ContentItemRepository; +import org.librecms.contentsection.ContentSection; +import org.librecms.contentsection.ContentSectionConfig; +import org.librecms.contentsection.privileges.ItemPrivileges; +import org.librecms.lifecycle.Lifecycle; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.text.DateFormat; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.Optional; + +/** + * This class contains the component which displays the information for a + * particular lifecycle, with the ability to edit and delete. This information + * also includes the associated phases for this lifecycle, also with the ability + * to add, edit, and delete. + * + * @author Michael Pih + * @author Jack Chung + * @author Xixi D'Moon + * @author Justin Ross + * @author Jens Pelzetter + */ +class ItemLifecycleItemPane extends BaseItemPane { + + private static final Logger LOGGER = LogManager.getLogger( + ItemLifecycleItemPane.class); + private final ContentItemRequestLocal selectedItem; + private final LifecycleRequestLocal selectedLifecycle; + private final SimpleContainer detailPane; + + public ItemLifecycleItemPane(final ContentItemRequestLocal selectedItem, + final LifecycleRequestLocal selectedLifecycle) { + this.selectedItem = selectedItem; + this.selectedLifecycle = selectedLifecycle; + + detailPane = new SimpleContainer(); + add(detailPane); + setDefault(detailPane); + + detailPane.add(new SummarySection()); + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final ContentItemRepository itemRepo = cdiUtil.findBean( + ContentItemRepository.class); + final ContentItemManager itemManager = cdiUtil.findBean( + ContentItemManager.class); + final GlobalizationHelper globalizationHelper = cdiUtil.findBean( + GlobalizationHelper.class); + + final Label lastPublishedLabel = new Label(); + lastPublishedLabel.addPrintListener(new PrintListener() { + + @Override + public void prepare(final PrintEvent event) { + final PageState state = event.getPageState(); + final Optional item = itemManager.getLiveVersion( + selectedItem.getContentItem(state), ContentItem.class); + final Label label = (Label) event.getTarget(); + final String dateStr; + if (item.isPresent()) { + final Date lastModifiedDate = itemRepo + .retrieveCurrentRevision(item.get(), + item.get().getObjectId()) + .getRevisionDate(); + dateStr = DateFormat.getDateTimeInstance( + DateFormat.LONG, + DateFormat.SHORT, + globalizationHelper.getNegotiatedLocale()) + .format(lastModifiedDate); + } else { + dateStr = ""; + } + + label.setLabel(new GlobalizedMessage( + "cms.ui.lifecycle.details.last_published", + CmsConstants.CMS_BUNDLE, + new Object[]{dateStr})); + } + + }); + detailPane.add(lastPublishedLabel); + + detailPane.add( + new PhaseSection()); + } + + private class SummarySection extends Section { + + public SummarySection() { + setHeading(new Label(gz("cms.ui.lifecycle.details"))); + + final ActionGroup group = new ActionGroup(); + setBody(group); + + if (CMSConfig.getConfig().isUseOldStyleItemLifecycleItemPane()) { + group.setSubject(new Properties()); + group.addAction(new UnpublishLink()); + group.addAction(new RepublishLink()); + group.addAction(new RepublishAndResetLink()); + } else { + group.addAction(new ActionForm()); + } + + } + + private class Properties extends PropertyList { + + @Override + protected final List properties(final PageState state) { + final List props = super.properties(state); + final Lifecycle cycle = selectedLifecycle.getLifecycle(state); + + final DateFormat format = DateFormat.getDateTimeInstance( + DateFormat.FULL, + DateFormat.FULL); + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final GlobalizationHelper globalizationHelper = cdiUtil + .findBean(GlobalizationHelper.class); + final Locale language = globalizationHelper + .getNegotiatedLocale(); + + props.add(new Property( + gz("cms.ui.name"), + cycle.getDefinition().getLabel().getValue(language))); + props.add(new Property( + gz("cms.ui.item.lifecycle.start_date"), + format.format(cycle.getStartDateTime()))); + + final java.util.Date endDate = cycle.getEndDateTime(); + + if (endDate == null) { + props.add(new Property(gz("cms.ui.item.lifecycle.end_date"), + lz("cms.ui.none"))); + } else { + props.add(new Property(gz("cms.ui.item.lifecycle.end_date"), + format.format(endDate))); + } + + return props; + } + + } + + } + + private class PublishLink extends ActionLink { + + private final RequestLocal canPublishRequestLocal = new RequestLocal(); + + PublishLink(final Component component) { + super(component); + } + + @Override + public void generateXML(final PageState state, final Element parent) { + Boolean canPublish = (Boolean) canPublishRequestLocal.get(state); + if (null == canPublish) { + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final PermissionChecker permissionChecker = cdiUtil.findBean( + PermissionChecker.class); + ContentItem item = selectedItem.getContentItem(state); + if (permissionChecker.isPermitted(ItemPrivileges.PUBLISH, item)) { + canPublish = true; + } else { + canPublish = false; + } + + canPublishRequestLocal.set(state, canPublish); + } + + if (canPublish) { + if (LOGGER.isDebugEnabled()) { + final ContentItem item = selectedItem.getContentItem(state); + LOGGER.debug("User can publish {}" + item.getUuid()); + } + + super.generateXML(state, parent); + } else if (LOGGER.isDebugEnabled()) { + final ContentItem item = selectedItem.getContentItem(state); + LOGGER.debug("User cannot publish {}", item.getUuid()); + } + } + + } + + private class UnpublishLink extends PublishLink { + + UnpublishLink() { + super(new Label(gz("cms.ui.item.lifecycle.unpublish"))); + + addActionListener(new Listener()); + } + + private class Listener implements ActionListener { + + @Override + public final void actionPerformed(final ActionEvent event) { + final PageState state = event.getPageState(); + final ContentItem item = selectedItem.getContentItem(state); + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final ContentItemManager itemManager = cdiUtil.findBean( + ContentItemManager.class); + + itemManager.unpublish(item); + + final String target = String.join( + "", + URL.getDispatcherPath(), + ContentItemPage.getItemURL(item, + ContentItemPage.AUTHORING_TAB)); + + throw new RedirectSignal(target, true); + } + + } + + } + + private static void republish(final ContentItem item, + final boolean reset, + final User user) { + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final ContentItemManager itemManager = cdiUtil.findBean( + ContentItemManager.class); + final WorkflowManager workflowManager = cdiUtil.findBean( + WorkflowManager.class); + + itemManager.publish(item); + + workflowManager.finish(item.getWorkflow()); + } + + private class RepublishLink extends PublishLink { + + RepublishLink() { + super(new Label(gz("cms.ui.item.lifecycle.republish"))); + + addActionListener(new Listener()); + } + + private class Listener implements ActionListener { + + @Override + public final void actionPerformed(final ActionEvent event) { + final PageState state = event.getPageState(); + final ContentItem item = selectedItem.getContentItem(state); + final User user = Web.getWebContext().getUser(); + + /* + * jensp 2011-12-14: Check is threaded publishing is active. If yes, execute publishing in a thread. + */ + if (CMSConfig.getConfig().isThreadPublishing()) { + final Republisher republisher = new Republisher(item, user); + final Thread thread = new Thread(republisher); + thread.setUncaughtExceptionHandler( + new Thread.UncaughtExceptionHandler() { + + @Override + public void uncaughtException(final Thread thread, + final Throwable ex) { + final StringWriter strWriter = new StringWriter(); + final PrintWriter writer + = new PrintWriter(strWriter); + ex.printStackTrace(writer); + + PublishLock.getInstance().setError(item, strWriter + .toString()); + LOGGER.error(String.format( + "An error occurred while " + + "publishing the item '%s': ", + item.getOID().toString()), + ex); + + if ((CMSConfig.getInstanceOf(). + getPublicationFailureSender() + == null) + && (CMSConfig.getInstanceOf(). + getPublicationFailureReceiver() + == null)) { + return; + } + + final PartyCollection receiverParties = Party + .retrieveAllParties(); + Party receiver = null; + receiverParties.addEqualsFilter("primaryEmail", + CMSConfig + .getInstanceOf() + .getPublicationFailureReceiver()); + if (receiverParties.next()) { + receiver = receiverParties.getParty(); + } + receiverParties.close(); + + final PartyCollection senderParties = Party + .retrieveAllParties(); + Party sender = null; + senderParties.addEqualsFilter("primaryEmail", + CMSConfig + .getInstanceOf(). + getPublicationFailureReceiver()); + if (senderParties.next()) { + sender = senderParties.getParty(); + } + senderParties.close(); + + if ((sender != null) && (receiver != null)) { + final Writer traceWriter = new StringWriter(); + final PrintWriter printWriter = new PrintWriter( + traceWriter); + ex.printStackTrace(printWriter); + + final Notification notification + = new Notification( + sender, + receiver, + String.format( + "Failed to publish item '%s'", + item.getOID().toString()), + String.format( + "Publishing item '%s' failed " + + "with error message: %s.\n\n" + + "Stacktrace:\n%s", + item.getOID().toString(), + ex.getMessage(), + traceWriter.toString())); + notification.save(); + } + } + + }); + + thread.start(); + + throw new RedirectSignal( + URL.getDispatcherPath() + + ContentItemPage.getItemURL(item, + ContentItemPage.PUBLISHING_TAB), + true); + /* + * jensp 2011-12-14 end + */ + } else { + republish(item, false, user); + if (ContentSection.getConfig().getUseStreamlinedCreation()) { + throw new RedirectSignal( + URL.there(state.getRequest(), + ContentCenter.getURL()), true); + } + } + } + + } + + /** + * @author Jens Pelzetter + */ + private class Republisher implements Runnable { + + /** + * Saves OID of item as a string. This is necessary because it is + * not possible to access to same data object instance from multiple + * threads. So we have to create a new instance a the data object in + * the run method. To avoid any sort a problems, we store the OID as + * a string and convert it back to an OID in the run method. + */ + private final String itemOid; + private final User user; + + private Republisher(final ContentItem item, User user) { + itemOid = item.getOID().toString(); + this.user = user; + } + + @Override + public void run() { + final ContentItem item = (ContentItem) DomainObjectFactory + .newInstance(OID.valueOf( + itemOid)); + PublishLock.getInstance().lock(item); + republish(item, false, user); + PublishLock.getInstance().unlock(item); + } + + } + + } + + private class RepublishAndResetLink extends PublishLink { + + RepublishAndResetLink() { + super(new Label(gz("cms.ui.item.lifecycle.republish_and_reset"))); + + addActionListener(new Listener()); + // warning gets a bit annoying, and link should be descriptive + // enough that it is not required + // setConfirmation("This will reset all your publication dates, are + // you sure you want to continue?"); + } + + private class Listener implements ActionListener { + + @Override + public final void actionPerformed(final ActionEvent e) { + final PageState state = e.getPageState(); + final ContentItem item = selectedItem.getContentItem(state); + final User user = Web.getWebContext().getUser(); + + /** + * jensp 2011-12-14: Execute is a thread if threaded publishing + * is active. + */ + if (CMSConfig.getInstanceOf().getThreadedPublishing()) { + final Republisher republisher = new Republisher(item, user); + final Thread thread = new Thread(republisher); + thread.setUncaughtExceptionHandler( + new Thread.UncaughtExceptionHandler() { + + @Override + public void uncaughtException(final Thread thread, + final Throwable ex) { + final StringWriter strWriter = new StringWriter(); + final PrintWriter writer + = new PrintWriter(strWriter); + ex.printStackTrace(writer); + + PublishLock.getInstance().setError(item, strWriter + .toString()); + LOGGER.error(String.format( + "An error occurred while " + + "publishing the item '%s': ", + item.getOID().toString()), + ex); + + if ((CMSConfig.getInstanceOf(). + getPublicationFailureSender() + == null) + && (CMSConfig.getInstanceOf(). + getPublicationFailureReceiver() + == null)) { + return; + } + + final PartyCollection receiverParties = Party + .retrieveAllParties(); + Party receiver = null; + receiverParties.addEqualsFilter("primaryEmail", + CMSConfig + .getInstanceOf() + .getPublicationFailureReceiver()); + if (receiverParties.next()) { + receiver = receiverParties.getParty(); + } + receiverParties.close(); + + final PartyCollection senderParties = Party + .retrieveAllParties(); + Party sender = null; + senderParties.addEqualsFilter("primaryEmail", + CMSConfig + .getInstanceOf(). + getPublicationFailureReceiver()); + if (senderParties.next()) { + sender = senderParties.getParty(); + } + senderParties.close(); + + if ((sender != null) && (receiver != null)) { + final Writer traceWriter = new StringWriter(); + final PrintWriter printWriter = new PrintWriter( + traceWriter); + ex.printStackTrace(printWriter); + + final Notification notification + = new Notification( + sender, + receiver, + String.format( + "Failed to publish item '%s'", + item.getOID().toString()), + String.format( + "Publishing item '%s' failed " + + "with error message: %s.\n\n" + + "Stacktrace:\n%s", + item.getOID().toString(), + ex.getMessage(), + traceWriter.toString())); + notification.save(); + } + } + + }); + + thread.start(); + + throw new RedirectSignal( + URL.getDispatcherPath() + + ContentItemPage.getItemURL(item, + ContentItemPage.PUBLISHING_TAB), + true); + } else { + /** + * jensp 2011-12-14 end + */ + republish(item, true, user); + if (ContentSection.getConfig().getUseStreamlinedCreation()) { + throw new RedirectSignal( + URL.there(state.getRequest(), + ContentCenter.getURL()), true); + } + } + } + + } + + /** + * @author Jens Pelzetter + */ + private class Republisher implements Runnable { + + /** + * Saves OID of item as a string. This is necessary because it is + * not possible to access to same data object instance from multiple + * threads. So we have to create a new instance a the data object in + * the run method. To avoid any sort a problems, we store the OID as + * a string and convert it back to an OID in the run method. + */ + private final String itemOid; + private final User user; + + private Republisher(final ContentItem item, User user) { + itemOid = item.getOID().toString(); + this.user = user; + } + + @Override + public void run() { + final ContentItem item = (ContentItem) DomainObjectFactory + .newInstance(OID.valueOf( + itemOid)); + PublishLock.getInstance().lock(item); + republish(item, true, user); + PublishLock.getInstance().unlock(item); + } + + } + + } + + private class PhaseSection extends Section { + + PhaseSection() { + super(gz("cms.ui.lifecycle.phases")); + + final ActionGroup group = new ActionGroup(); + setBody(group); + + group.setSubject(new PhaseTable()); + } + + } + + private class PhaseTable extends Table { + + PhaseTable() { + super(new ItemPhaseTableModelBuilder(selectedLifecycle), + new String[]{ + lz("cms.ui.name"), + lz("cms.ui.description"), + lz("cms.ui.item.lifecycle.start_date"), + lz("cms.ui.item.lifecycle.end_date") + }); + } + + } + + /** + * New style pane. Uses a select box for the action to avoid wrong clicks on + * unpublish. + * + * @author Jens Pelzetter + */ + private class ActionForm + extends Form + implements FormProcessListener, + FormInitListener { + + private static final String LIFECYCLE_ACTION + = "itemLifecycleItemPaneActionSelect"; + private static final String REPUBLISH = "republish"; + private static final String UNPUBLISH = "unpublish"; + private static final String REPUBLISH_AND_RESET = "republishAndReset"; + private final Submit submit; + private final Label notAuthorized; + + public ActionForm() { + super("itemLifecycleItemPaneActionForm"); + + final BoxPanel actionPanel = new BoxPanel(BoxPanel.HORIZONTAL); + final SingleSelect actionSelect = new SingleSelect( + LIFECYCLE_ACTION); + + actionSelect.addOption(new Option(REPUBLISH, (String) gz( + "cms.ui.item.lifecycle.republish") + .localize())); + if (!ContentSection.getConfig().hideResetLifecycleLink()) { + actionSelect.addOption(new Option(REPUBLISH_AND_RESET, + (String) gz( + "cms.ui.item.lifecycle.republish_and_reset") + .localize())); + } + actionSelect.addOption(new Option(UNPUBLISH, (String) gz( + "cms.ui.item.lifecycle.unpublish") + .localize())); + + submit = new Submit(gz("cms.ui.item.lifecycle.do")); + notAuthorized = new Label(gz( + "cms.ui.item.lifecycle.do.not_authorized")); + + actionPanel.add(actionSelect); + actionPanel.add(submit); + actionPanel.add(notAuthorized); + add(actionPanel); + + addInitListener(this); + addProcessListener(this); + } + + @Override + public void init(FormSectionEvent fse) throws FormProcessException { + final PageState state = fse.getPageState(); + final ContentItem item = selectedItem.getContentItem(state); + + final SecurityManager sm = Utilities.getSecurityManager(state); + + if (sm.canAccess(state.getRequest(), + SecurityManager.PUBLISH, + item)) { + submit.setVisible(state, true); + notAuthorized.setVisible(state, false); + } else { + submit.setVisible(state, false); + notAuthorized.setVisible(state, true); + } + } + + @Override + public void process(final FormSectionEvent fse) throws + FormProcessException { + final PageState state = fse.getPageState(); + final FormData data = fse.getFormData(); + final User user = Web.getWebContext().getUser(); + + String selected = (String) data.get(LIFECYCLE_ACTION); + final ContentItem item = selectedItem.getContentItem(state); + + /** + * Republish/Republish and Reset are executed in the thread if + * threaded publishing is active. + */ + if (REPUBLISH.equals(selected)) { + if (CMSConfig.getInstanceOf().getThreadedPublishing()) { + final RepublishRunner runner = new RepublishRunner(item, + user); + final Thread thread = new Thread(runner); + thread.setUncaughtExceptionHandler( + new Thread.UncaughtExceptionHandler() { + + @Override + public void uncaughtException(final Thread thread, + final Throwable ex) { + final StringWriter strWriter = new StringWriter(); + final PrintWriter writer + = new PrintWriter(strWriter); + ex.printStackTrace(writer); + + PublishLock.getInstance().setError(item, strWriter + .toString()); + LOGGER.error(String.format( + "An error occurred while " + + "publishing the item '%s': ", + item.getOID().toString()), + ex); + + if ((CMSConfig.getInstanceOf(). + getPublicationFailureSender() + == null) + && (CMSConfig.getInstanceOf(). + getPublicationFailureReceiver() + == null)) { + return; + } + + final PartyCollection receiverParties = Party + .retrieveAllParties(); + Party receiver = null; + receiverParties.addEqualsFilter("primaryEmail", + CMSConfig + .getInstanceOf() + .getPublicationFailureReceiver()); + if (receiverParties.next()) { + receiver = receiverParties.getParty(); + } + receiverParties.close(); + + final PartyCollection senderParties = Party + .retrieveAllParties(); + Party sender = null; + senderParties.addEqualsFilter("primaryEmail", + CMSConfig + .getInstanceOf(). + getPublicationFailureReceiver()); + if (senderParties.next()) { + sender = senderParties.getParty(); + } + senderParties.close(); + + if ((sender != null) && (receiver != null)) { + final Writer traceWriter = new StringWriter(); + final PrintWriter printWriter = new PrintWriter( + traceWriter); + ex.printStackTrace(printWriter); + + final Notification notification + = new Notification( + sender, + receiver, + String.format( + "Failed to publish item '%s'", + item.getOID().toString()), + String.format( + "Publishing item '%s' failed " + + "with error message: %s.\n\n" + + "Stacktrace:\n%s", + item.getOID().toString(), + ex.getMessage(), + traceWriter.toString())); + notification.save(); + } + } + + }); + + thread.start(); + + throw new RedirectSignal( + URL.getDispatcherPath() + + ContentItemPage.getItemURL(item, + ContentItemPage.PUBLISHING_TAB), + true); + } else { + republish(item, false, user); + + if (ContentSection.getConfig().getUseStreamlinedCreation()) { + throw new RedirectSignal( + URL.there(state.getRequest(), + ContentCenter.getURL()), true); + } + } + } else if (REPUBLISH_AND_RESET.equals(selected)) { + if (CMSConfig.getInstanceOf().getThreadedPublishing()) { + final RepublishAndResetRunner runner + = new RepublishAndResetRunner( + item, user); + final Thread thread = new Thread(runner); + thread.setUncaughtExceptionHandler( + new Thread.UncaughtExceptionHandler() { + + @Override + public void uncaughtException(final Thread thread, + final Throwable ex) { + final StringWriter strWriter = new StringWriter(); + final PrintWriter writer + = new PrintWriter(strWriter); + ex.printStackTrace(writer); + + PublishLock.getInstance().setError(item, strWriter + .toString()); + LOGGER.error(String.format( + "An error occurred while " + + "publishing the item '%s': ", + item.getOID().toString()), + ex); + + if ((CMSConfig.getInstanceOf(). + getPublicationFailureSender() + == null) + && (CMSConfig.getInstanceOf(). + getPublicationFailureReceiver() + == null)) { + return; + } + + final PartyCollection receiverParties = Party + .retrieveAllParties(); + Party receiver = null; + receiverParties.addEqualsFilter("primaryEmail", + CMSConfig + .getInstanceOf() + .getPublicationFailureReceiver()); + if (receiverParties.next()) { + receiver = receiverParties.getParty(); + } + receiverParties.close(); + + final PartyCollection senderParties = Party + .retrieveAllParties(); + Party sender = null; + senderParties.addEqualsFilter("primaryEmail", + CMSConfig + .getInstanceOf(). + getPublicationFailureReceiver()); + if (senderParties.next()) { + sender = senderParties.getParty(); + } + senderParties.close(); + + if ((sender != null) && (receiver != null)) { + final Writer traceWriter = new StringWriter(); + final PrintWriter printWriter = new PrintWriter( + traceWriter); + ex.printStackTrace(printWriter); + + final Notification notification + = new Notification( + sender, + receiver, + String.format( + "Failed to publish item '%s'", + item.getOID().toString()), + String.format( + "Publishing item '%s' failed " + + "with error message: %s.\n\n" + + "Stacktrace:\n%s", + item.getOID().toString(), + ex.getMessage(), + traceWriter.toString())); + notification.save(); + } + } + + }); + + thread.start(); + + throw new RedirectSignal( + URL.getDispatcherPath() + + ContentItemPage.getItemURL(item, + ContentItemPage.PUBLISHING_TAB), + true); + } else { + republish(item, true, user); + + if (ContentSection.getConfig().getUseStreamlinedCreation()) { + throw new RedirectSignal( + URL.there(state.getRequest(), + ContentCenter.getURL()), true); + } + } + } else if (UNPUBLISH.equals(selected)) { + item.unpublish(); + } else { + throw new IllegalArgumentException("Illegal selection"); + } + } + + private class RepublishRunner implements Runnable { + + /** + * Saves OID of item as a string. This is necessary because it is + * not possible to access to same data object instance from multiple + * threads. So we have to create a new instance a the data object in + * the run method. To avoid any sort a problems, we store the OID as + * a string and convert it back to an OID in the run method. + */ + private final String itemOid; + private final User user; + + private RepublishRunner(final ContentItem item, User user) { + itemOid = item.getOID().toString(); + this.user = user; + } + + private void doRepublish() { + final ContentItem item = (ContentItem) DomainObjectFactory + .newInstance(OID.valueOf( + itemOid)); + republish(item, false, user); + } + + @Override + public void run() { + final ContentItem item = (ContentItem) DomainObjectFactory + .newInstance(OID.valueOf( + itemOid)); + PublishLock.getInstance().lock(item); + doRepublish(); + PublishLock.getInstance().unlock(item); + } + + } + + private class RepublishAndResetRunner implements Runnable { + + /** + * Saves OID of item as a string. This is necessary because it is + * not possible to access to same data object instance from multiple + * threads. So we have to create a new instance a the data object in + * the run method. To avoid any sort a problems, we store the OID as + * a string and convert it back to an OID in the run method. + */ + private final String itemOid; + private final User user; + + private RepublishAndResetRunner(final ContentItem item, User user) { + itemOid = item.getOID().toString(); + this.user = user; + } + + private void doRepublishAndReset() { + final ContentItem item = (ContentItem) DomainObjectFactory + .newInstance(OID.valueOf( + itemOid)); + republish(item, true, user); + } + + @Override + public void run() { + final ContentItem item = (ContentItem) DomainObjectFactory + .newInstance(OID.valueOf( + itemOid)); + PublishLock.getInstance().lock(item); + doRepublishAndReset(); + PublishLock.getInstance().unlock(item); + } + + } + + } + +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/ItemLifecycleSelectForm.java.todo b/ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/ItemLifecycleSelectForm.java.todo new file mode 100755 index 000000000..c6bbaf010 --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/ItemLifecycleSelectForm.java.todo @@ -0,0 +1,1024 @@ +/* + * Copyright (C) 2003-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.cms.ui.lifecycle; + +import com.arsdigita.bebop.BoxPanel; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.SimpleContainer; +import com.arsdigita.bebop.event.FormInitListener; +import com.arsdigita.bebop.event.FormProcessListener; +import com.arsdigita.bebop.event.FormSectionEvent; +import com.arsdigita.bebop.event.FormValidationListener; +import com.arsdigita.bebop.event.PrintEvent; +import com.arsdigita.bebop.event.PrintListener; +import com.arsdigita.bebop.form.Date; +import com.arsdigita.bebop.form.Option; +import com.arsdigita.bebop.form.SingleSelect; +import com.arsdigita.bebop.form.Submit; +import com.arsdigita.bebop.form.TextField; +import com.arsdigita.bebop.parameters.BigDecimalParameter; +import com.arsdigita.bebop.parameters.DateParameter; +import com.arsdigita.bebop.parameters.IntegerParameter; +import com.arsdigita.bebop.parameters.NumberInRangeValidationListener; +import com.arsdigita.cms.CMS; +import com.arsdigita.cms.CMSConfig; +import com.arsdigita.cms.ContentItem; +import com.arsdigita.cms.ContentSection; +import com.arsdigita.cms.ContentTypeLifecycleDefinition; +import com.arsdigita.cms.ContentCenter; +import com.arsdigita.cms.lifecycle.Lifecycle; +import com.arsdigita.cms.lifecycle.LifecycleDefinition; +import com.arsdigita.cms.lifecycle.LifecycleDefinitionCollection; +import com.arsdigita.cms.lifecycle.Phase; +import com.arsdigita.cms.lifecycle.PhaseCollection; +import com.arsdigita.cms.lifecycle.PhaseDefinitionCollection; +import com.arsdigita.cms.ui.BaseForm; +import com.arsdigita.cms.ui.ContentItemPage; +import com.arsdigita.cms.ui.item.ContentItemRequestLocal; +import com.arsdigita.cms.ui.item.ItemWorkflowRequestLocal; +import com.arsdigita.cms.ui.workflow.WorkflowRequestLocal; +import com.arsdigita.cms.util.GlobalizationUtil; +import com.arsdigita.cms.workflow.CMSEngine; +import com.arsdigita.cms.workflow.CMSTask; +import com.arsdigita.cms.workflow.CMSTaskType; +import com.arsdigita.domain.DomainObjectFactory; +import com.arsdigita.kernel.Party; +import com.arsdigita.kernel.PartyCollection; +import com.arsdigita.kernel.User; +import com.arsdigita.notification.Notification; +import com.arsdigita.persistence.OID; +import com.arsdigita.util.UncheckedWrapperException; +import com.arsdigita.web.RedirectSignal; +import com.arsdigita.web.URL; +import com.arsdigita.web.Web; +import com.arsdigita.workflow.simple.Engine; +import com.arsdigita.workflow.simple.TaskException; +import com.arsdigita.workflow.simple.Workflow; +import com.arsdigita.workflow.simple.WorkflowTemplate; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Calendar; +import java.util.Iterator; +import java.util.TimeZone; +import java.util.TooManyListenersException; +import javax.servlet.http.HttpServletRequest; +import org.apache.log4j.Logger; + +/** + *

+ * A form to select and apply a lifecycle to a content item.

+ * + * @author Michael Pih + * @author Xixi D'moon <xdmoon@redhat.com> + * @author Justin Ross <jross@redhat.com> + * @author Jens Pelzetter jens@jp-digital.de + * @version $Id: ItemLifecycleSelectForm.java 2267 2012-01-09 16:50:14Z pboy $ + */ +class ItemLifecycleSelectForm extends BaseForm { + + private static final Logger s_log + = Logger.getLogger(ItemLifecycleSelectForm.class); + private final static String LIFECYCLE = "lifecycle"; + private final static String START_DATE = "start_date"; + private final static String END_DATE = "end_date"; + private final static String NOTIFICATION_DAYS = "notifyDays"; + private final static String NOTIFICATION_HOURS = "notifyHours"; + private final ContentItemRequestLocal m_item; + private final WorkflowRequestLocal m_workflow; + // Form widgets + private final SingleSelect m_cycleSelect; + private final Date m_startDate; + private final TextField m_startHour; + private final TextField m_startMinute; + private final SingleSelect m_startAmpm; + private final Date m_endDate; + private final TextField m_endHour; + private final TextField m_endMinute; + private final SingleSelect m_endAmpm; + private TextField m_notificationDays; + private TextField m_notificationHours; + + public ItemLifecycleSelectForm(final ContentItemRequestLocal item) { + super("PublishItem", gz("cms.ui.item.lifecycle.apply")); + + m_item = item; + m_workflow = new ItemWorkflowRequestLocal(); + + m_cycleSelect = new SingleSelect(new BigDecimalParameter(LIFECYCLE)); + try { + m_cycleSelect.addPrintListener(new OptionPrinter()); + } catch (TooManyListenersException tmle) { + throw new UncheckedWrapperException(tmle); + } + addField(gz("cms.ui.item.lifecycle"), m_cycleSelect); + + // Start date + m_startDate = new Date(new DateParameter(START_DATE) { + + @Override + protected final Calendar getCalendar(final HttpServletRequest sreq) { + final Calendar cal = super.getCalendar(sreq); + + cal.setLenient(false); + + return cal; + } + + }); + addField(gz("cms.ui.item.lifecycle.start_date"), m_startDate); + + // Start time + final BoxPanel startTime = new BoxPanel(BoxPanel.HORIZONTAL); + addField(gz("cms.ui.item.lifecycle.start_time"), startTime); + + // Hour + m_startHour = new TextField(new IntegerParameter("start_hour")); + startTime.add(m_startHour); + + m_startHour.setSize(3); + m_startHour.addValidationListener( + new NumberInRangeValidationListener(1, 12)); + + // Minute + m_startMinute = new TextField(new IntegerParameter("start_minute")); + startTime.add(m_startMinute); + + m_startMinute.setSize(3); + m_startMinute.addValidationListener(new NumberInRangeValidationListener( + 0, 59)); + + // AM/PM + m_startAmpm = new SingleSelect(new IntegerParameter("start_ampm")); + startTime.add(m_startAmpm); + + m_startAmpm.addOption(new Option("0", "am")); + m_startAmpm.addOption(new Option("1", "pm")); + + // Time zone + startTime.add(new Label(new TimeZonePrinter())); + + // Expiration date + m_endDate = new Date(new DateParameter(END_DATE) { + + @Override + protected final Calendar getCalendar(final HttpServletRequest sreq) { + final Calendar cal = super.getCalendar(sreq); + + cal.setLenient(false); + + return cal; + } + + }); + addField(gz("cms.ui.item.lifecycle.end_date"), m_endDate); + + // End time + final BoxPanel endTime = new BoxPanel(BoxPanel.HORIZONTAL); + addField(gz("cms.ui.item.lifecycle.end_time"), endTime); + + // Hour + m_endHour = new TextField(new IntegerParameter("end_hour")); + endTime.add(m_endHour); + + m_endHour.setSize(3); + m_endHour.addValidationListener(new NumberInRangeValidationListener(1, + 12)); + + // Minute + m_endMinute = new TextField(new IntegerParameter("end_minute")); + endTime.add(m_endMinute); + + m_endMinute.setSize(3); + m_endMinute.addValidationListener( + new NumberInRangeValidationListener(0, 59)); + + // AM/PM + m_endAmpm = new SingleSelect(new IntegerParameter("end_ampm")); + endTime.add(m_endAmpm); + + m_endAmpm.addOption(new Option("0", "am")); + m_endAmpm.addOption(new Option("1", "pm")); + + endTime.add(new Label(new TimeZonePrinter())); + + m_notificationDays = new TextField(new IntegerParameter(NOTIFICATION_DAYS)); + m_notificationDays.setSize(4); + m_notificationHours = new TextField(new IntegerParameter(NOTIFICATION_HOURS)); + m_notificationHours.setSize(4); + SimpleContainer cont = new SimpleContainer(); + cont.add(m_notificationDays); + cont.add(new Label(GlobalizationUtil.globalize("cms.ui.item.days"), + false)); + cont.add(m_notificationHours); + cont.add(new Label(GlobalizationUtil.globalize("cms.ui.item.hours"), + false)); + + addField(gz("cms.ui.item.notification_period"), cont); + + // A hidden field that checks to see if the user wants publish + // with a start time earlier than current time. + addAction(new Submit("finish", gz("cms.ui.item.lifecycle.publish"))); + + // Form listeners + addValidationListener(new ValidationListener()); + addSecurityListener(PUBLISH, m_item); + addInitListener(new InitListener()); + addProcessListener(new ProcessListener()); + } + + private class OptionPrinter implements PrintListener { + + @Override + public final void prepare(final PrintEvent e) { + final ContentSection section = CMS.getContext().getContentSection(); + + final LifecycleDefinitionCollection ldc = section.getLifecycleDefinitions(); + ldc.addOrder("label"); + + final SingleSelect target = (SingleSelect) e.getTarget(); + target.clearOptions(); + + while (ldc.next()) { + final LifecycleDefinition ld = ldc.getLifecycleDefinition(); + final PhaseDefinitionCollection pdc = ld.getPhaseDefinitions(); + + // XXX domlay this seems a little weak. perhaps + // there's a better way to determine if a lifecycle is + // ready to be applied to an item. + if (!pdc.isEmpty()) { + target.addOption(new Option(ld.getID().toString(), + ld.getLabel())); + } + + pdc.close(); + } + + ldc.close(); + } + + } + + private class InitListener implements FormInitListener { + + @Override + public final void init(final FormSectionEvent e) { + final PageState state = e.getPageState(); + + final ContentItem item = m_item.getContentItem(state); + + if (item.isPublished()) { + // If the item is published, select the currently + // associated lifecycle. + + final LifecycleDefinition ld = item.getLifecycle(). + getLifecycleDefinition(); + m_cycleSelect.setValue(state, ld.getID()); + } else { + // Set the default lifecycle (if it exists). + + final ContentSection section = CMS.getContext().getContentSection(); + final LifecycleDefinition ld = ContentTypeLifecycleDefinition. + getLifecycleDefinition(section, item.getContentType()); + + if (ld != null) { + m_cycleSelect.setValue(state, ld.getID()); + } + } + + // Set the default start date. + // XXX Isn't just new Date() sufficient? + final java.util.Date start = new java.util.Date(System. + currentTimeMillis()); + m_startDate.setValue(state, start); + + final Calendar calendar = Calendar.getInstance(); + calendar.setTime(start); + + // If the hour is 12, then Calendar.get(Calendar.HOUR) + // returns 0 (from the 24 hour time - 12). We want it to + // return 12. + if (calendar.get(Calendar.HOUR) == 0) { + m_startHour.setValue(state, new Integer(12)); + } else { + m_startHour.setValue(state, new Integer(calendar.get( + Calendar.HOUR))); + } + + final Integer min = new Integer(calendar.get(Calendar.MINUTE)); + + if (min.intValue() < 10) { + m_startMinute.setValue(state, "0" + min.toString()); + } else { + m_startMinute.setValue(state, min.toString()); + } + + m_startAmpm.setValue(state, + new Integer(calendar.get(Calendar.AM_PM))); + + BigInteger[] defaultTime = BigInteger.valueOf(ContentSection.getConfig(). + getDefaultNotificationTime()). + divideAndRemainder(BigInteger.valueOf(24)); + + m_notificationDays.setValue(state, new Integer(defaultTime[0]. + intValue())); + m_notificationHours.setValue(state, new Integer(defaultTime[1]. + intValue())); + } + + } + + /** + * jensp 2011-12-14: Some larger changes to the behavior of the process + * listener. The real action has been moved to the + * @link{Publisher} class. If threaded publishing is active, the publish + * process runs in a separate thread (the item is locked before using + * {@link PublishLock}. If threaded publishing is not active, nothing has + * changed. + */ + private class ProcessListener implements FormProcessListener { + + @Override + public final void process(final FormSectionEvent e) + throws FormProcessException { + final PageState state = e.getPageState(); + final ContentItem item = m_item.getContentItem(state); + + final Publisher publisher = new Publisher(state); + if (CMSConfig.getInstanceOf().getThreadedPublishing()) { + final Runnable threadAction = new Runnable() { + + @Override + public void run() { + PublishLock.getInstance().lock(item); + publisher.publish(); + PublishLock.getInstance().unlock(item); + } + + }; + final Thread thread = new Thread(threadAction); + thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + + @Override + public void uncaughtException(final Thread thread, + final Throwable ex) { + final StringWriter strWriter = new StringWriter(); + final PrintWriter writer = new PrintWriter(strWriter); + ex.printStackTrace(writer); + + PublishLock.getInstance().setError(item, strWriter.toString()); + s_log.error(String.format( + "An error occurred while " + + "publishing the item '%s': ", + item.getOID().toString()), + ex); + + if ((CMSConfig.getInstanceOf().getPublicationFailureSender() + == null) + && (CMSConfig.getInstanceOf(). + getPublicationFailureReceiver() == null)) { + return; + } + + final PartyCollection receiverParties = Party. + retrieveAllParties(); + Party receiver = null; + receiverParties.addEqualsFilter("primaryEmail", + CMSConfig.getInstanceOf(). + getPublicationFailureReceiver()); + if (receiverParties.next()) { + receiver = receiverParties.getParty(); + } + receiverParties.close(); + + final PartyCollection senderParties = Party. + retrieveAllParties(); + Party sender = null; + senderParties.addEqualsFilter("primaryEmail", CMSConfig. + getInstanceOf().getPublicationFailureReceiver()); + if (senderParties.next()) { + sender = senderParties.getParty(); + } + senderParties.close(); + + if ((sender != null) && (receiver != null)) { + final Writer traceWriter = new StringWriter(); + final PrintWriter printWriter = new PrintWriter( + traceWriter); + ex.printStackTrace(printWriter); + + final Notification notification = new Notification( + sender, + receiver, + String.format("Failed to publish item '%s'", + item.getOID().toString()), + String.format("Publishing item '%s' failed " + + "with error message: %s.\n\n" + + "Stacktrace:\n%s", + item.getOID().toString(), + ex.getMessage(), + traceWriter.toString())); + notification.save(); + } + } + + }); + thread.start(); + } else { + publisher.publish(); + } + + if (CMSConfig.getInstanceOf().getThreadedPublishing()) { + throw new RedirectSignal( + URL.getDispatcherPath() + + ContentItemPage.getItemURL(item, + ContentItemPage.PUBLISHING_TAB), + true); + } else { + if (ContentSection.getConfig().getUseStreamlinedCreation()) { + throw new RedirectSignal( + URL.there(state.getRequest(), + ContentCenter.getURL()), + true); + } + } + + /* + * final Integer startHour = (Integer) m_startHour.getValue(state); + * Integer startMinute = (Integer) m_startMinute.getValue(state); + * + * if (startMinute == null) { startMinute = new Integer(0); } + * + * final Integer startAmpm = (Integer) m_startAmpm.getValue(state); + * + * final Integer endHour = (Integer) m_endHour.getValue(state); + * Integer endMinute = (Integer) m_endMinute.getValue(state); + * + * if (endMinute == null) { endMinute = new Integer(0); } + * + * final Integer endAmpm = (Integer) m_endAmpm.getValue(state); + * + * // Instantiate the instance of the content type. final + * ContentItem item = m_item.getContentItem(state); + * + * final BigDecimal defID = (BigDecimal) + * m_cycleSelect.getValue(state); Assert.exists(defID); final + * LifecycleDefinition cycleDef = new LifecycleDefinition(defID); + * + * java.util.Date startDate = (java.util.Date) + * m_startDate.getValue(state); + * + * final Calendar start = Calendar.getInstanceOf(); + * start.setTime(startDate); start.set(Calendar.AM_PM, + * startAmpm.intValue()); start.set(Calendar.MINUTE, + * startMinute.intValue()); start.set(Calendar.AM_PM, + * startAmpm.intValue()); if (startHour.intValue() != 12) { + * start.set(Calendar.HOUR_OF_DAY, 12 * startAmpm.intValue() + + * startHour.intValue()); start.set(Calendar.HOUR, + * startHour.intValue()); } else { if (startAmpm.intValue() == 0) { + * start.set(Calendar.HOUR_OF_DAY, 0); start.set(Calendar.HOUR, 0); + * } else { start.set(Calendar.HOUR_OF_DAY, 12); + * start.set(Calendar.HOUR, 0); } } startDate = start.getTime(); + * + * java.util.Date endDate = (java.util.Date) + * m_endDate.getValue(state); + * + * if (endDate != null) { final Calendar end = + * Calendar.getInstanceOf(); + * + * end.setTime(endDate); end.set(Calendar.AM_PM, + * endAmpm.intValue()); end.set(Calendar.MINUTE, + * endMinute.intValue()); end.set(Calendar.AM_PM, + * endAmpm.intValue()); + * + * if (endHour.intValue() != 12) { end.set(Calendar.HOUR_OF_DAY, 12 + * * endAmpm.intValue() + endHour.intValue()); + * end.set(Calendar.HOUR, endHour.intValue()); } else { if + * (endAmpm.intValue() == 0) { end.set(Calendar.HOUR_OF_DAY, 0); + * end.set(Calendar.HOUR, 0); } else { end.set(Calendar.HOUR_OF_DAY, + * 12); end.set(Calendar.HOUR, 0); } } endDate = end.getTime(); } + * + * // If the item is already published, remove the current + * lifecycle. // Do not touch the live version. if + * (item.isPublished()) { item.removeLifecycle(item); item.save(); } + * + * // Apply the new lifecycle. ContentItem pending = + * item.publish(cycleDef, startDate); final Lifecycle lifecycle = + * pending.getLifecycle(); + * + * // XXX domlay Whoa. This must be broken for multiphase // + * lifecycles. + * + * if (endDate != null) { + * + * // update individual phases final PhaseCollection phases = + * lifecycle.getPhases(); + * + * while (phases.next()) { final Phase phase = phases.getPhase(); + * java.util.Date thisEnd = phase.getEndDate(); java.util.Date + * thisStart = phase.getStartDate(); if + * (thisStart.compareTo(endDate) > 0) { phase.setStartDate(endDate); + * phase.save(); } + * + * if (thisEnd == null || thisEnd.compareTo(endDate) > 0) { + * phase.setEndDate(endDate); phase.save(); } } } + * + * // endOfCycle may be the original date according to lifecycle + * phase definitions, or endDate if that was before // natural end + * of lifecycle java.util.Date endOfCycle = lifecycle.getEndDate(); + * if (endOfCycle != null) { + * + * // if advance notification is requested (!= 0) // add another + * phase at the start of which the user is notified Integer + * notificationDays = (Integer) m_notificationDays.getValue(state); + * Integer notificationHours = (Integer) + * m_notificationHours.getValue(state); java.util.Date + * notificationDate = null; + * + * int notificationPeriod = 0; if (notificationDays != null) { + * notificationPeriod += notificationDays.intValue() * 24; } if + * (notificationHours != null) { notificationPeriod += + * notificationHours.intValue(); } + * + * if (notificationPeriod > 0) { notificationDate = + * computeNotificationDate(endOfCycle, notificationPeriod); + * s_log.debug("adding custom phase"); Phase expirationImminentPhase + * = lifecycle.addCustomPhase("expirationImminent", new + * Long(notificationDate. getTime()), new + * Long(endOfCycle.getTime())); + * expirationImminentPhase.setListenerClassName( + * "com.arsdigita.cms.lifecycle.NotifyLifecycleListener"); + * expirationImminentPhase.save(); } } + * + * // Force the lifecycle scheduler to run to avoid any // + * scheduler delay for items that should be published // + * immediately. pending.getLifecycle().start(); + * + * item.save(); + * + * final Workflow workflow = m_workflow.getWorkflow(state); try { + * finish(workflow, item, Web.getWebContext().getUser()); } catch + * (TaskException te) { throw new FormProcessException(te); } // + * redirect to /content-center if streamlined creation mode is + * active. if + * (ContentSection.getConfig().getUseStreamlinedCreation()) { throw + * new RedirectSignal(URL.there(state.getRequest(), + * Utilities.getWorkspaceURL()), true); } + */ + } + + } + + /** + * This class contains the real publish action. + */ + private class Publisher { + + private final Integer startHour; + private final Integer startMinute; + private final Integer startAmpm; + private final Integer endHour; + private final Integer endMinute; + private final Integer endAmpm; + private final String oidStr; + private final BigDecimal defID; + private final java.util.Date startDate; + private final java.util.Date endDate; + private final Integer notificationDays; + private final Integer notificationHours; + private final String workflowOid; + private final User user; + + /** + * The constructor collects all necessary data and stores them. + * + * @param state + */ + public Publisher(final PageState state) { + startHour = (Integer) m_startHour.getValue(state); + if (m_startMinute.getValue(state) == null) { + startMinute = new Integer(0); + } else { + startMinute = (Integer) m_startMinute.getValue(state); + } + startAmpm = (Integer) m_startAmpm.getValue(state); + + endHour = (Integer) m_endHour.getValue(state); + if (m_endMinute.getValue(state) == null) { + endMinute = new Integer(0); + } else { + endMinute = (Integer) m_endMinute.getValue(state); + } + endAmpm = (Integer) m_endAmpm.getValue(state); + + //item = m_item.getContentItem(state); + oidStr = m_item.getContentItem(state).getOID().toString(); + + defID = (BigDecimal) m_cycleSelect.getValue(state); + + final Calendar start = Calendar.getInstance(); + start.setTime((java.util.Date) m_startDate.getValue(state)); + start.set(Calendar.AM_PM, startAmpm.intValue()); + start.set(Calendar.MINUTE, startMinute.intValue()); + start.set(Calendar.AM_PM, startAmpm.intValue()); + if (startHour.intValue() != 12) { + start.set(Calendar.HOUR_OF_DAY, + 12 * startAmpm.intValue() + startHour.intValue()); + start.set(Calendar.HOUR, startHour.intValue()); + } else { + if (startAmpm.intValue() == 0) { + start.set(Calendar.HOUR_OF_DAY, 0); + start.set(Calendar.HOUR, 0); + } else { + start.set(Calendar.HOUR_OF_DAY, 12); + start.set(Calendar.HOUR, 0); + } + } + startDate = start.getTime(); + + if (m_endDate.getValue(state) == null) { + endDate = null; + } else { + final Calendar end = Calendar.getInstance(); + + end.setTime((java.util.Date) m_endDate.getValue(state)); + end.set(Calendar.AM_PM, endAmpm.intValue()); + end.set(Calendar.MINUTE, endMinute.intValue()); + end.set(Calendar.AM_PM, endAmpm.intValue()); + + if (endHour.intValue() != 12) { + end.set(Calendar.HOUR_OF_DAY, + 12 * endAmpm.intValue() + endHour.intValue()); + end.set(Calendar.HOUR, endHour.intValue()); + } else { + if (endAmpm.intValue() == 0) { + end.set(Calendar.HOUR_OF_DAY, 0); + end.set(Calendar.HOUR, 0); + } else { + end.set(Calendar.HOUR_OF_DAY, 12); + end.set(Calendar.HOUR, 0); + } + } + endDate = end.getTime(); + } + + notificationDays = (Integer) m_notificationDays.getValue(state); + notificationHours = (Integer) m_notificationHours.getValue(state); + + if (m_workflow.getWorkflow(state) != null) { + workflowOid = m_workflow.getWorkflow(state).getOID().toString(); + } else { + workflowOid = null; + } + + user = Web.getWebContext().getUser(); + } + + /** + * Published the item + */ + public void publish() { + + /** + * We have to create a new instance here since it is not possible to + * access the same data object from multiple threads. + */ + final OID oid = OID.valueOf(oidStr); + final ContentItem item = (ContentItem) DomainObjectFactory. + newInstance(oid); + + // If the item is already published, remove the current lifecycle. + // Do not touch the live version. + if (item.isPublished()) { + item.removeLifecycle(item); + item.save(); + } + + ContentItem pending; + final LifecycleDefinition cycleDef; + final Lifecycle lifecycle; + // Apply the new lifecycle. + cycleDef = new LifecycleDefinition(defID); + pending = item.publish(cycleDef, startDate); + lifecycle = pending.getLifecycle(); + + // XXX domlay Whoa. This must be broken for multiphase + // lifecycles. + if (endDate != null) { + + // update individual phases + final PhaseCollection phases = lifecycle.getPhases(); + + while (phases.next()) { + final Phase phase = phases.getPhase(); + java.util.Date thisEnd = phase.getEndDate(); + java.util.Date thisStart = phase.getStartDate(); + if (thisStart.compareTo(endDate) > 0) { + phase.setStartDate(endDate); + phase.save(); + } + + if (thisEnd == null || thisEnd.compareTo(endDate) > 0) { + phase.setEndDate(endDate); + phase.save(); + } + } + } + + // endOfCycle may be the original date according to lifecycle phase definitions, or endDate if that was before + // natural end of lifecycle + java.util.Date endOfCycle = lifecycle.getEndDate(); + if (endOfCycle != null) { + + // if advance notification is requested (!= 0) + // add another phase at the start of which the user is notified + java.util.Date notificationDate = null; + + int notificationPeriod = 0; + if (notificationDays != null) { + notificationPeriod += notificationDays.intValue() * 24; + } + if (notificationHours != null) { + notificationPeriod += notificationHours.intValue(); + } + + if (notificationPeriod > 0) { + notificationDate = computeNotificationDate(endOfCycle, notificationPeriod); + s_log.debug("adding custom phase"); + Phase expirationImminentPhase = lifecycle.addCustomPhase("expirationImminent", + new Long( + notificationDate. + getTime()), + new Long(endOfCycle. + getTime())); + expirationImminentPhase.setListenerClassName( + "com.arsdigita.cms.lifecycle.NotifyLifecycleListener"); + expirationImminentPhase.save(); + } + } + + // Force the lifecycle scheduler to run to avoid any + // scheduler delay for items that should be published + // immediately. + pending.getLifecycle().start(); + + item.save(); + + if (workflowOid != null) { + final Workflow workflow = (Workflow) DomainObjectFactory.newInstance(OID. + valueOf(workflowOid)); + try { + finish(workflow, item, user); + } catch (TaskException ex) { + throw new UncheckedWrapperException(ex); + } + } + } + + } + + static void finish(Workflow workflow, ContentItem item, User user) throws + TaskException { + if ((workflow != null) && (user != null)) { + final Engine engine = Engine.getInstance(CMSEngine.CMS_ENGINE_TYPE); + // ; + + final Iterator iter = engine.getEnabledTasks(user, workflow.getID()). + iterator(); + + while (iter.hasNext()) { + final CMSTask task = (CMSTask) iter.next(); + if (s_log.isDebugEnabled()) { + s_log.debug("Task is " + task.getOID().toString()); + } + if (task.getTaskType().getID().equals(CMSTaskType.DEPLOY)) { + s_log.debug("Found DEPLOY task, ID=" + CMSTaskType.DEPLOY); + task.finish(user); + } + } + if (ContentSection.getConfig().getDeleteWorkflowAfterPublication()) { + workflow.delete(); + } else { + // restart the workflow by recreating it + // from the same workflow template + WorkflowTemplate t = workflow.getWorkflowTemplate(); + workflow.delete(); + workflow = t.instantiateNewWorkflow(); + workflow.setObject(item); + /* Startring the workflow will probably do the wrong thing, because most of the time + * the current user would be a publisher, not an author */ +// workflow.start(user); + workflow.save(); + } + } + } + + private class ValidationListener implements FormValidationListener { + + @Override + public void validate(FormSectionEvent e) throws FormProcessException { + final PageState state = e.getPageState(); + + final Integer startHour = (Integer) m_startHour.getValue(state); + if (startHour == null) { + throw new FormProcessException(GlobalizationUtil.globalize( + "cms.ui.item.start_time_incomplete")); + } + + Integer startMinute = (Integer) m_startMinute.getValue(state); + if (startMinute == null) { + startMinute = new Integer(0); + } + + Integer startAmpm = (Integer) m_startAmpm.getValue(state); + + java.util.Date startDate = (java.util.Date) m_startDate.getValue( + state); + if (startDate == null) { + throw new FormProcessException(GlobalizationUtil.globalize( + "cms.ui.item.lifecycle.start_date_invalid")); + } + + java.util.Date nowDate = new java.util.Date(System.currentTimeMillis()); + + Calendar cStart = Calendar.getInstance(); + Calendar cNow = Calendar.getInstance(); + cStart.setTime(startDate); + cNow.setTime(nowDate); + + if (startHour.intValue() != 12) { + cStart.set(Calendar.HOUR_OF_DAY, + 12 * startAmpm.intValue() + startHour.intValue()); + cStart.set(Calendar.HOUR, startHour.intValue()); + } else { + if (startAmpm.intValue() == 0) { + cStart.set(Calendar.HOUR_OF_DAY, 0); + cStart.set(Calendar.HOUR, 0); + } else { + cStart.set(Calendar.HOUR_OF_DAY, 12); + cStart.set(Calendar.HOUR, 0); + } + } + + // Give the user extra 5 minutes before form complains + // start time's in the past. + cStart.set(Calendar.MINUTE, startMinute.intValue() + 5); + cStart.set(Calendar.AM_PM, startAmpm.intValue()); + cStart.set(Calendar.SECOND, cNow.get(Calendar.SECOND)); + cStart.set(Calendar.MILLISECOND, cNow.get(Calendar.MILLISECOND)); + + if (cNow.after(cStart)) { + throw new FormProcessException(GlobalizationUtil.globalize( + "cms.ui.item.lifecycle.start_date_in_past")); + } + + Integer endHour = (Integer) m_endHour.getValue(state); + Integer endMinute = (Integer) m_endMinute.getValue(state); + java.util.Date endDate = (java.util.Date) m_endDate.getValue(state); + + if (endHour == null && (endMinute != null || endDate != null)) { + throw new FormProcessException(GlobalizationUtil.globalize( + "cms.ui.item.lifecycle.end_time_incomplete")); + } + + if (endMinute == null && endHour != null) { + endMinute = new Integer(0); + } + + boolean timeBlank = (endHour == null) && (endMinute == null); + + Integer endAmpm = (Integer) m_endAmpm.getValue(state); + + if (endDate == null && !timeBlank) { + throw new FormProcessException(GlobalizationUtil.globalize( + "cms.ui.item.lifecycle.end_date_invalid")); + } + + if (endDate != null) { + Calendar cEnd = Calendar.getInstance(); + cEnd.setTime(endDate); + + if (endHour.intValue() != 12) { + cEnd.set(Calendar.HOUR_OF_DAY, + 12 * endAmpm.intValue() + endHour.intValue()); + cEnd.set(Calendar.HOUR, endHour.intValue()); + } else { + if (endAmpm.intValue() == 0) { + cEnd.set(Calendar.HOUR_OF_DAY, 0); + cEnd.set(Calendar.HOUR, 0); + } else { + cEnd.set(Calendar.HOUR_OF_DAY, 12); + cEnd.set(Calendar.HOUR, 0); + } + } + + // Give the user extra 5 minutes before form complains + // end time's in the past. + cEnd.set(Calendar.MINUTE, endMinute.intValue() + 5); + cEnd.set(Calendar.AM_PM, endAmpm.intValue()); + cEnd.set(Calendar.SECOND, cNow.get(Calendar.SECOND)); + cEnd.set(Calendar.MILLISECOND, cNow.get(Calendar.MILLISECOND)); + + //check if the end date is prior to the start date + if (cStart.after(cEnd)) { + throw new FormProcessException(GlobalizationUtil.globalize( + "cms.ui.item.lifecycle.end_date_before_start_date")); + } + + Integer notificationDays = (Integer) m_notificationDays.getValue(state); + Integer notificationHours = (Integer) m_notificationHours.getValue(state); + + int notificationPeriod = 0; + if (notificationDays != null) { + notificationPeriod += notificationDays.intValue() * 24; + } + if (notificationHours != null) { + notificationPeriod += notificationHours.intValue(); + } + + if (notificationPeriod > 0) { + // point in time for notification == end date - notificationPeriod + java.util.Date notificationDate = computeNotificationDate(cEnd.getTime(), + notificationPeriod); + s_log.debug("cStart (Date): " + cStart.getTime()); + s_log.debug("notificationDate: " + notificationDate); + // complain if date for notification is before the start date + if (notificationDate.before(cStart.getTime())) { + s_log.debug("notification date is before start date!"); + + throw new FormProcessException(GlobalizationUtil.globalize("cms.ui.item.notification_period_before_start")); + } else { + s_log.debug("notification date is after start date, OK"); + } + } + } + } + + } + + public class TimeZonePrinter implements PrintListener { + + @Override + public void prepare(PrintEvent e) { + final Label target = (Label) e.getTarget(); + if (ContentSection.getConfig().getHideTimezone()) { + target.setLabel(""); + } else { + final PageState state = e.getPageState(); + final Calendar mStart = Calendar.getInstance(); + java.util.Date st = (java.util.Date) m_startDate.getValue(state); + + if (st != null) { + mStart.setTime((java.util.Date) m_startDate.getValue(state)); + } + + final String zone = mStart.getTimeZone().getDisplayName(true, + TimeZone.SHORT); + + target.setLabel(zone); + } + } + + } + + /** + * Find out at which date a notification (about an item that is about to + * expire) should be sent, based on the endDate (== date at which the item + * is unpublished) and the notification period. + * + * @param endDate the endDate of the lifecycle, i.e. the date when the item + * is going to be unpublished + * @param notification how many hours the users shouls be notified in + * advance + */ + private java.util.Date computeNotificationDate(java.util.Date endDate, + int notificationPeriod) { + if (endDate == null) { + return null; + } + + return new java.util.Date(endDate.getTime() - (long) notificationPeriod + * 3600000L); + } + +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/LifecycleAdminPane.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/LifecycleAdminPane.java.todo similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/LifecycleAdminPane.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/LifecycleAdminPane.java.todo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/LifecycleItemPane.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/LifecycleItemPane.java.todo similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/LifecycleItemPane.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/LifecycleItemPane.java.todo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/LifecycleRequestLocal.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/LifecycleRequestLocal.java new file mode 100755 index 000000000..3d3c9066d --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/lifecycle/LifecycleRequestLocal.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2003-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.cms.ui.lifecycle; + +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.RequestLocal; + +import org.librecms.lifecycle.Lifecycle; + +public abstract class LifecycleRequestLocal extends RequestLocal { + + public final Lifecycle getLifecycle(final PageState state) { + return (Lifecycle) get(state); + } +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/role/BaseRoleItemPane.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/role/BaseRoleItemPane.java.todo similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/role/BaseRoleItemPane.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/role/BaseRoleItemPane.java.todo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/role/RoleAdminPane.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/role/RoleAdminPane.java.todo similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/role/RoleAdminPane.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/role/RoleAdminPane.java.todo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/search/ItemQueryComponent.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/search/ItemQueryComponent.java.todo similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/search/ItemQueryComponent.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/search/ItemQueryComponent.java.todo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/type/ContentTypePropertyList.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/type/ContentTypePropertyList.java index fa02a1b54..7c2ebd20e 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/type/ContentTypePropertyList.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/type/ContentTypePropertyList.java @@ -20,16 +20,23 @@ package com.arsdigita.cms.ui.type; import com.arsdigita.bebop.PageState; import com.arsdigita.cms.CMS; + import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.ContentType; import org.librecms.lifecycle.LifecycleDefinition; + import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.kernel.KernelConfig; +import com.arsdigita.toolbox.ui.Property; import com.arsdigita.toolbox.ui.PropertyList; + import java.util.Locale; + import org.libreccm.workflow.WorkflowTemplate; import org.librecms.CmsConstants; +import java.util.List; + /** * This component displays basic attributes of a content type * including: @@ -50,8 +57,8 @@ class ContentTypePropertyList extends PropertyList { } @Override - protected final java.util.List properties(final PageState state) { - final java.util.List props = super.properties(state); + protected final List properties(final PageState state) { + final List props = super.properties(state); final ContentType type = m_type.getContentType(state); final ContentSection section = CMS.getContext().getContentSection(); diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/BaseWorkflowItemPane.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/BaseWorkflowItemPane.java index 28bb14015..34f476f79 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/BaseWorkflowItemPane.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/BaseWorkflowItemPane.java @@ -38,6 +38,7 @@ import org.librecms.workflow.CmsTask; import org.libreccm.security.User; import com.arsdigita.toolbox.ui.ActionGroup; +import com.arsdigita.toolbox.ui.Property; import com.arsdigita.toolbox.ui.PropertyList; import com.arsdigita.toolbox.ui.Section; diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskItemPane.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskItemPane.java index 10fdce4b7..ec5b8d833 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskItemPane.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskItemPane.java @@ -39,6 +39,7 @@ import org.librecms.workflow.CmsTask; import org.libreccm.security.User; import com.arsdigita.toolbox.ui.ActionGroup; +import com.arsdigita.toolbox.ui.Property; import com.arsdigita.toolbox.ui.PropertyList; import com.arsdigita.toolbox.ui.Section; import com.arsdigita.util.LockableImpl; diff --git a/ccm-cms/src/main/java/org/librecms/CmsConstants.java b/ccm-cms/src/main/java/org/librecms/CmsConstants.java index aff817cef..715c86692 100644 --- a/ccm-cms/src/main/java/org/librecms/CmsConstants.java +++ b/ccm-cms/src/main/java/org/librecms/CmsConstants.java @@ -59,6 +59,8 @@ public class CmsConstants { public static final String ASSET_ID = "asset_id"; public static final String IMAGE_ID = "image_id"; + + public final static String SCHEDULE_PUBLICATION = "schedule_publication"; private CmsConstants() { //Nothing diff --git a/ccm-core/src/main/java/com/arsdigita/toolbox/ui/ContextBar.java b/ccm-core/src/main/java/com/arsdigita/toolbox/ui/ContextBar.java index 422cd5f04..c0f039d77 100755 --- a/ccm-core/src/main/java/com/arsdigita/toolbox/ui/ContextBar.java +++ b/ccm-core/src/main/java/com/arsdigita/toolbox/ui/ContextBar.java @@ -24,24 +24,23 @@ import com.arsdigita.bebop.RequestLocal; import com.arsdigita.web.URL; import com.arsdigita.util.Assert; import com.arsdigita.xml.Element; + import java.util.Iterator; import java.util.ArrayList; import java.util.List; -import org.apache.log4j.Logger; /** *

A context bar.

* - * @author Justin Ross <jross@redhat.com> - * @version $Id$ + * @author Justin Ross + * @author Jens Pelzetter */ public abstract class ContextBar extends SimpleComponent { - private static final Logger s_log = Logger.getLogger(ContextBar.class); - - private static final RequestLocal s_entries = new RequestLocal() { + private static final RequestLocal ENTRIES = new RequestLocal() { + @Override protected final Object initialValue(final PageState state) { - return new ArrayList(); + return new ArrayList<>(); } }; @@ -49,17 +48,19 @@ public abstract class ContextBar extends SimpleComponent { super(); } - protected List entries(final PageState state) { - return (List) s_entries.get(state); + @SuppressWarnings("unchecked") + protected List entries(final PageState state) { + return (List) ENTRIES.get(state); } + @Override public final void generateXML(final PageState state, final Element parent) { if (isVisible(state)) { final Element nav = parent.newChildElement ("bebop:contextBar", BEBOP_XML_NS); - for (Iterator iter = entries(state).iterator(); iter.hasNext(); ) { - ((Entry) iter.next()).generateXML(state, nav); + for (Iterator iter = entries(state).iterator(); iter.hasNext(); ) { + iter.next().generateXML(state, nav); } } } diff --git a/ccm-core/src/main/java/com/arsdigita/toolbox/ui/Property.java b/ccm-core/src/main/java/com/arsdigita/toolbox/ui/Property.java new file mode 100644 index 000000000..52f27ecbb --- /dev/null +++ b/ccm-core/src/main/java/com/arsdigita/toolbox/ui/Property.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package com.arsdigita.toolbox.ui; + +import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.PageState; +import com.arsdigita.globalization.GlobalizedMessage; +import com.arsdigita.util.Assert; +import com.arsdigita.xml.Element; + +/** + * + * @author Jens Pelzetter + */ +public final class Property { + + private final String title; + private final String value; + + public Property(final String title, final String value) { + super(); + Assert.exists(title, "String title"); + this.title = title; + this.value = value; + } + + public Property(final GlobalizedMessage title, final String value) { + this(title.localize().toString(), value); + } + + public Property(final GlobalizedMessage title, final GlobalizedMessage value) { + this(title.localize().toString(), value.localize().toString()); + } + + public Property(final String title, final GlobalizedMessage value) { + this(title, value.localize().toString()); + } + + public void generateXML(final PageState state, final Element parent) { + final Element elem = parent.newChildElement("bebop:property", + Component.BEBOP_XML_NS); + elem.addAttribute("title", title); + elem.addAttribute("value", value); + } + +} diff --git a/ccm-core/src/main/java/com/arsdigita/toolbox/ui/PropertyList.java b/ccm-core/src/main/java/com/arsdigita/toolbox/ui/PropertyList.java index 0bc31837b..09b0ce50c 100755 --- a/ccm-core/src/main/java/com/arsdigita/toolbox/ui/PropertyList.java +++ b/ccm-core/src/main/java/com/arsdigita/toolbox/ui/PropertyList.java @@ -24,79 +24,45 @@ import com.arsdigita.bebop.RequestLocal; import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.util.Assert; import com.arsdigita.xml.Element; + import java.util.Iterator; import java.util.ArrayList; import java.util.List; -import org.apache.log4j.Logger; /** - *

A context bar.

* - * @author Justin Ross <jross@redhat.com> + * @author Justin Ross + * @author Jens Pelzetter */ public abstract class PropertyList extends SimpleComponent { - private static final Logger s_log = Logger.getLogger(PropertyList.class); + private static final RequestLocal PROPERTIES = new RequestLocal() { - private static final RequestLocal s_props = new RequestLocal() { - protected final Object initialValue(final PageState state) { - return new ArrayList(); - } - }; + @Override + protected final Object initialValue(final PageState state) { + return new ArrayList<>(); + } + + }; public PropertyList() { super(); } - protected List properties(final PageState state) { - return (List) s_props.get(state); + @SuppressWarnings("unchecked") + protected List properties(final PageState state) { + return (List) PROPERTIES.get(state); } + @Override public final void generateXML(final PageState state, final Element parent) { if (isVisible(state)) { - final Element nav = parent.newChildElement - ("bebop:propertyList", BEBOP_XML_NS); + final Element nav = parent.newChildElement("bebop:propertyList", + BEBOP_XML_NS); - for (Iterator iter = properties(state).iterator(); - iter.hasNext(); ) { - ((Property) iter.next()).generateXML(state, nav); - } + properties(state).forEach(property -> property.generateXML(state, + nav)); } } - public static final class Property { - private final String m_title; - private final String m_value; - - public Property(final String title, final String value) { - super(); - - Assert.exists(title, "String title"); - - m_title = title; - m_value = value; - } - - public Property(final GlobalizedMessage title, final String value) { - this(title.localize().toString(), value); - } - - public Property(final GlobalizedMessage title, - final GlobalizedMessage value) { - this(title.localize().toString(), value.localize().toString()); - } - - public Property(final String title, final GlobalizedMessage value) { - this(title, value.localize().toString()); - } - - public void generateXML(final PageState state, - final Element parent) { - final Element elem = parent.newChildElement - ("bebop:property", BEBOP_XML_NS); - - elem.addAttribute("title", m_title); - elem.addAttribute("value", m_value); - } - } } diff --git a/ccm-core/src/main/java/org/libreccm/auditing/AbstractAuditedEntityRepository.java b/ccm-core/src/main/java/org/libreccm/auditing/AbstractAuditedEntityRepository.java index f6bbc8303..1710d2afa 100644 --- a/ccm-core/src/main/java/org/libreccm/auditing/AbstractAuditedEntityRepository.java +++ b/ccm-core/src/main/java/org/libreccm/auditing/AbstractAuditedEntityRepository.java @@ -25,7 +25,9 @@ import org.hibernate.envers.query.AuditQuery; import org.libreccm.core.AbstractEntityRepository; import javax.inject.Inject; + import java.util.List; +import java.util.stream.Collectors; /** * @@ -81,15 +83,50 @@ public abstract class AbstractAuditedEntityRepository final Long objectId) { return auditReader.getRevisions(entity.getClass(), objectId); } - + + /** + * Retrieves the first revision of the given entity. + * + * @param entity The entity. + * @param objectId The primary key of the entity. + * + * @return The first revision of the entity. + */ public CcmRevision retrieveFirstRevision(final T entity, final Long objectId) { final List revisions = retrieveRevisionNumbersOfEntity( entity, objectId); - + return auditReader.findRevision(CcmRevision.class, revisions.get(0)); } + /** + * Retrieves all revisions of the given entity. The list of revisions is + * ordered from the oldest revision to the newest revision. + * + * @param entity The entity. + * @param objectId The primary key of the entity. + * + * @return A list of all revisions of the provided entity. + */ + public List retrieveRevisions(final T entity, + final Long objectId) { + final List revisionNumbers = retrieveRevisionNumbersOfEntity( + entity, objectId); + + return revisionNumbers.stream() + .map(revisionNumber -> auditReader.findRevision(CcmRevision.class, + revisionNumber)) + .collect(Collectors.toList()); + } + + /** + * Retrieves the current revision of an entity. + * + * @param entity The entity. + * @param objectId the primary key the entity. + * @return The most current revision of the entity. + */ public CcmRevision retrieveCurrentRevision(final T entity, final Long objectId) { final List revisions = retrieveRevisionNumbersOfEntity(