From b7f54a9921e81b83f918e76b06fb0cdf0e14a1a9 Mon Sep 17 00:00:00 2001 From: jensp Date: Wed, 14 Dec 2011 15:18:43 +0000 Subject: [PATCH] =?UTF-8?q?Verbesserung=20der=20Publizieren-Formulars:=20?= =?UTF-8?q?=09-=20Der=20eigentliche=20Vorgang=20wird=20jetzt=20nebenl?= =?UTF-8?q?=C3=A4ufig=20durchgef=C3=BChrt=20=09-=20Solange=20der=20Vorgang?= =?UTF-8?q?=20noch=20l=C3=A4uft=20wird=20eine=20entsprechende=20Meldung=20?= =?UTF-8?q?angezeigt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: https://svn.libreccm.org/ccm/trunk@1352 8810af33-2d31-482b-a856-94f89814c4df --- .../upgrade/6.6.2-6.6.3/upd_table_persons.sql | 20 - .../ccm-cms/upgrade/postgres-6.6.2-6.6.3.sql | 1 + ccm-cms/src/com/arsdigita/cms/CMSConfig.java | 24 +- .../cms/CMSConfig_parameter.properties | 5 + .../com/arsdigita/cms/CMSResources.properties | 2 + .../arsdigita/cms/CMSResources_de.properties | 2 + .../cms/CMSResources_en_GB.properties | 2 + .../arsdigita/cms/CMSResources_fr.properties | 2 + .../ui/lifecycle/ItemLifecycleAdminPane.java | 65 +- .../ui/lifecycle/ItemLifecycleItemPane.java | 232 ++++++- .../ui/lifecycle/ItemLifecycleSelectForm.java | 593 +++++++++++++----- 11 files changed, 728 insertions(+), 220 deletions(-) diff --git a/ccm-cms/sql/ccm-cms/default/upgrade/6.6.2-6.6.3/upd_table_persons.sql b/ccm-cms/sql/ccm-cms/default/upgrade/6.6.2-6.6.3/upd_table_persons.sql index 110806017..c3af3c349 100644 --- a/ccm-cms/sql/ccm-cms/default/upgrade/6.6.2-6.6.3/upd_table_persons.sql +++ b/ccm-cms/sql/ccm-cms/default/upgrade/6.6.2-6.6.3/upd_table_persons.sql @@ -26,23 +26,3 @@ ALTER TABLE cms_persons ALTER TABLE cms_persons ADD COLUMN dabin_id INTEGER; - -CREATE TABLE cms_organizationalunits_hierarchy_map ( - superior_orgaunit_id integer NOT NULL, - subordinate_orgaunit_id integer NOT NULL, - assoc_type character varying(128), - superior_orgaunit_order integer, - subordinate_orgaunit_order integer -); - --- No sure how to get db owner here -ALTER TABLE public.cms_organizationalunits_hierarchy_map OWNER TO iaw; - -ALTER TABLE ONLY cms_organizationalunits_hierarchy_map - ADD CONSTRAINT cms_org_hie_map_sub_or_p_nykpq PRIMARY KEY (subordinate_orgaunit_id, superior_orgaunit_id); - -ALTER TABLE ONLY cms_organizationalunits_hierarchy_map - ADD CONSTRAINT cms_org_hie_map_sub_or_f_xq5is FOREIGN KEY (subordinate_orgaunit_id) REFERENCES cms_organizationalunits(organizationalunit_id); - -ALTER TABLE ONLY cms_organizationalunits_hierarchy_map - ADD CONSTRAINT cms_org_hie_map_sup_or_f_qchkn FOREIGN KEY (superior_orgaunit_id) REFERENCES cms_organizationalunits(organizationalunit_id); \ No newline at end of file diff --git a/ccm-cms/sql/ccm-cms/upgrade/postgres-6.6.2-6.6.3.sql b/ccm-cms/sql/ccm-cms/upgrade/postgres-6.6.2-6.6.3.sql index 76b408d90..363cf5ac5 100644 --- a/ccm-cms/sql/ccm-cms/upgrade/postgres-6.6.2-6.6.3.sql +++ b/ccm-cms/sql/ccm-cms/upgrade/postgres-6.6.2-6.6.3.sql @@ -27,5 +27,6 @@ begin; \i ../default/upgrade/6.6.2-6.6.3/upd_table_persons.sql \i ../default/upgrade/6.6.2-6.6.3/create_orgaunit_hierarchy_table.sql +\i ../default/upgrade/6.6.2-6.6.3/create_publish_lock_table.sql commit; diff --git a/ccm-cms/src/com/arsdigita/cms/CMSConfig.java b/ccm-cms/src/com/arsdigita/cms/CMSConfig.java index 191171c20..c0aa466ba 100755 --- a/ccm-cms/src/com/arsdigita/cms/CMSConfig.java +++ b/ccm-cms/src/com/arsdigita/cms/CMSConfig.java @@ -587,6 +587,19 @@ public final class CMSConfig extends AbstractConfig { "com.arsdigita.cms.lifecycle.use_old_style_item_lifecycle_item_pane", Parameter.REQUIRED, false); + + //////////////////////////////////////////////// + //Actives threaded publishing. If active, the publish process for + //content items will run in a separate thread. May useful if you have + //large objects. + // + //WARNING: Not tested very much. Use at your own risk. + // + //////////////////////////////////////////////////// + private final Parameter m_threadPublishing = new BooleanParameter( + "com.arsdigita.cms.lifecycle.threaded_publishing", + Parameter.REQUIRED, + false); // /////////////////////////////////////////// // publishToFile package related parameter @@ -651,7 +664,7 @@ public final class CMSConfig extends AbstractConfig { register(m_categoryTreeOrdering); register(m_hasContactsAuthoringStep); register(m_hideTextAssetUploadFile); - register(m_allowContentCreateInSectionListing); + register(m_allowContentCreateInSectionListing); // Content Center (Workspace) config related parameters register(m_contentCenterMap); @@ -667,8 +680,9 @@ public final class CMSConfig extends AbstractConfig { register(m_folderBrowseListSize); register(m_folderAtoZShowLimit); - + register(m_useOldStyleItemLifecycleItemPane); + register(m_threadPublishing); // publishToFile package related parameter // Moved to publishToFile.PublishToFileConfig as of version 6.0.2 @@ -1067,8 +1081,12 @@ public final class CMSConfig extends AbstractConfig { public Integer getFolderAtoZShowLimit() { return (Integer) get(m_folderAtoZShowLimit); } - + public Boolean getUseOldStyleItemLifecycleItemPane() { return (Boolean) get(m_useOldStyleItemLifecycleItemPane); } + + public Boolean getThreadedPublishing() { + return (Boolean) get(m_threadPublishing); + } } diff --git a/ccm-cms/src/com/arsdigita/cms/CMSConfig_parameter.properties b/ccm-cms/src/com/arsdigita/cms/CMSConfig_parameter.properties index 58f57ad1b..ee5bcb8d9 100755 --- a/ccm-cms/src/com/arsdigita/cms/CMSConfig_parameter.properties +++ b/ccm-cms/src/com/arsdigita/cms/CMSConfig_parameter.properties @@ -254,6 +254,11 @@ com.arsdigita.cms.lifecycle.use_old_style_item_lifecycle_item_pane.purpose = If com.arsdigita.cms.lifecycle.use_old_style_item_lifecycle_item_pane.example = false com.arsdigita.cms.lifecycle.use_old_style_item_lifecycle_item_pane.format = [Boolean] +com.arsdigita.cms.lifecycle.threaded_publishing.title = Threaded publishing +com.arsdigita.cms.lifecycle.threaded_publishing.purpose = Decides if publishing is done in a thread (new behaviour) or directly (old, well tested behaviour). +com.arsdigita.cms.lifecycle.threaded_publishing.example = false +com.arsdigita.cms.lifecycle.threaded_com.arsdigita.cms.lifecycle.threaded_publishingpublishing.format = [Boolean] + com.arsdigita.cms.xx.title= com.arsdigita.cms.xx.purpose= com.arsdigita.cms.xx.example= diff --git a/ccm-cms/src/com/arsdigita/cms/CMSResources.properties b/ccm-cms/src/com/arsdigita/cms/CMSResources.properties index a60fb72fb..8d29ac6c5 100755 --- a/ccm-cms/src/com/arsdigita/cms/CMSResources.properties +++ b/ccm-cms/src/com/arsdigita/cms/CMSResources.properties @@ -1087,3 +1087,5 @@ cms.contenttypes.person.alias.select.same_as_person=Selected person is the same cms.contenttypes.person.alias.select.no_suitable_language_variant=The selected item has no suitable language variant. cms.ui.item.lifecycle.do=Execute cms.ui.item.lifecycle.do.not_authorized=Your not authorized to publish this item. +cms.ui.item.lifecycle.publish_locked=This content item is being (re-)published +cms.ui.item.lifecycle.publish_locked.update=Update diff --git a/ccm-cms/src/com/arsdigita/cms/CMSResources_de.properties b/ccm-cms/src/com/arsdigita/cms/CMSResources_de.properties index ae2c5f567..f798bc6e5 100755 --- a/ccm-cms/src/com/arsdigita/cms/CMSResources_de.properties +++ b/ccm-cms/src/com/arsdigita/cms/CMSResources_de.properties @@ -1078,3 +1078,5 @@ cms.contenttypes.person.alias.select.same_as_person=Der ausgew\u00e4hlte Datensa cms.contenttypes.person.alias.select.no_suitable_language_variant=Das ausgew\u00e4hlte Item hat keine passende Sprachvariante. cms.ui.item.lifecycle.do=Ausf\u00fchren cms.ui.item.lifecycle.do.not_authorized=Sie sind nicht berechtigt, dieses Item zu publizieren. +cms.ui.item.lifecycle.publish_locked=Dieses Content-Item wird gerade (re-)publiziert +cms.ui.item.lifecycle.publish_locked.update=Aktualisieren diff --git a/ccm-cms/src/com/arsdigita/cms/CMSResources_en_GB.properties b/ccm-cms/src/com/arsdigita/cms/CMSResources_en_GB.properties index 6a99dd290..1d4c86b18 100755 --- a/ccm-cms/src/com/arsdigita/cms/CMSResources_en_GB.properties +++ b/ccm-cms/src/com/arsdigita/cms/CMSResources_en_GB.properties @@ -26,3 +26,5 @@ cms.contenttypes.person.alias.select.same_as_person= cms.contenttypes.person.alias.select.no_suitable_language_variant= cms.ui.item.lifecycle.do= cms.ui.item.lifecycle.do.not_authorized= +cms.ui.item.lifecycle.publish_locked= +cms.ui.item.lifecycle.publish_locked.update= diff --git a/ccm-cms/src/com/arsdigita/cms/CMSResources_fr.properties b/ccm-cms/src/com/arsdigita/cms/CMSResources_fr.properties index 01b0e3b6f..5c50fd261 100755 --- a/ccm-cms/src/com/arsdigita/cms/CMSResources_fr.properties +++ b/ccm-cms/src/com/arsdigita/cms/CMSResources_fr.properties @@ -557,3 +557,5 @@ cms.contenttypes.person.alias.select.same_as_person= cms.contenttypes.person.alias.select.no_suitable_language_variant= cms.ui.item.lifecycle.do= cms.ui.item.lifecycle.do.not_authorized= +cms.ui.item.lifecycle.publish_locked= +cms.ui.item.lifecycle.publish_locked.update= diff --git a/ccm-cms/src/com/arsdigita/cms/ui/lifecycle/ItemLifecycleAdminPane.java b/ccm-cms/src/com/arsdigita/cms/ui/lifecycle/ItemLifecycleAdminPane.java index fc579d851..b4400a192 100755 --- a/ccm-cms/src/com/arsdigita/cms/ui/lifecycle/ItemLifecycleAdminPane.java +++ b/ccm-cms/src/com/arsdigita/cms/ui/lifecycle/ItemLifecycleAdminPane.java @@ -18,36 +18,41 @@ */ package com.arsdigita.cms.ui.lifecycle; +import com.arsdigita.bebop.ControlLink; import com.arsdigita.bebop.Label; 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.cms.CMS; +import com.arsdigita.cms.CMSConfig; import com.arsdigita.cms.ContentItem; import com.arsdigita.cms.lifecycle.Lifecycle; import com.arsdigita.cms.ui.BaseItemPane; +import com.arsdigita.cms.ui.ContentItemPage; import com.arsdigita.cms.ui.item.ContentItemRequestLocal; import com.arsdigita.toolbox.ui.LayoutPanel; +import com.arsdigita.web.RedirectSignal; +import com.arsdigita.web.URL; import org.apache.log4j.Logger; /** * @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 $ */ public class ItemLifecycleAdminPane extends BaseItemPane { - private static final Logger s_log = Logger.getLogger - (ItemLifecycleAdminPane.class); - + 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; public ItemLifecycleAdminPane(final ContentItemRequestLocal item) { m_item = item; @@ -63,20 +68,43 @@ public class ItemLifecycleAdminPane extends BaseItemPane { add(m_detailPane); final ItemLifecycleItemPane itemPane = - new ItemLifecycleItemPane(m_item, m_lifecycle); + new ItemLifecycleItemPane(m_item, + m_lifecycle); m_detailPane.setBody(itemPane); m_selectPane = new LayoutPanel(); add(m_selectPane); final ItemLifecycleSelectForm selectForm = - new ItemLifecycleSelectForm(m_item); + new ItemLifecycleSelectForm(m_item); m_selectPane.setBody(selectForm); + m_lockedPane = new LayoutPanel(); + add(m_lockedPane); + + final Label lockedMsg = new Label(gz( + "cms.ui.item.lifecycle.publish_locked")); + m_lockedPane.setBody(lockedMsg); + final ControlLink lockedUpdateLink = new ControlLink(new Label(gz( + "cms.ui.item.lifecycle.publish_locked.update"))); + lockedUpdateLink.addActionListener(new ActionListener() { + + public void actionPerformed(final ActionEvent event) { + throw new RedirectSignal( + URL.getDispatcherPath() + + ContentItemPage.getItemURL( + item.getContentItem(event.getPageState()), + ContentItemPage.PUBLISHING_TAB), + true); + } + }); + m_lockedPane.setBottom(lockedUpdateLink); + connect(selectForm, m_detailPane); } private class ItemLifecycleRequestLocal extends LifecycleRequestLocal { + protected final Object initialValue(final PageState state) { final ContentItem item = m_item.getContentItem(state); final Lifecycle lifecycle = item.getLifecycle(); @@ -94,20 +122,27 @@ 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"); final PageState state = e.getPageState(); - if (state.isVisibleOnPage(ItemLifecycleAdminPane.this)) { - if (m_lifecycle.getLifecycle(state) == null) { - if (hasPermission(state)) { - push(state, m_selectPane); + if (CMSConfig.getInstance().getThreadedPublishing() + && PublishLock.getInstance().isLocked(m_item.getContentItem( + state))) { + push(state, m_lockedPane); + } else { + if (state.isVisibleOnPage(ItemLifecycleAdminPane.this)) { + if (m_lifecycle.getLifecycle(state) == null) { + if (hasPermission(state)) { + push(state, m_selectPane); + } else { + push(state, m_introPane); + } } else { - push(state, m_introPane); + push(state, m_detailPane); } - } else { - push(state, m_detailPane); } } } @@ -116,7 +151,7 @@ public class ItemLifecycleAdminPane extends BaseItemPane { private boolean hasPermission(final PageState state) { final ContentItem item = m_item.getContentItem(state); - return CMS.getContext().getSecurityManager().canAccess - (state.getRequest(), SCHEDULE_PUBLICATION, item); + return CMS.getContext().getSecurityManager().canAccess( + state.getRequest(), SCHEDULE_PUBLICATION, item); } } diff --git a/ccm-cms/src/com/arsdigita/cms/ui/lifecycle/ItemLifecycleItemPane.java b/ccm-cms/src/com/arsdigita/cms/ui/lifecycle/ItemLifecycleItemPane.java index bbda7428e..adf8365b2 100755 --- a/ccm-cms/src/com/arsdigita/cms/ui/lifecycle/ItemLifecycleItemPane.java +++ b/ccm-cms/src/com/arsdigita/cms/ui/lifecycle/ItemLifecycleItemPane.java @@ -42,6 +42,7 @@ 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.CMSConfig; import com.arsdigita.cms.ContentItem; import com.arsdigita.cms.ContentSection; import com.arsdigita.cms.SecurityManager; @@ -50,6 +51,8 @@ import com.arsdigita.cms.lifecycle.Lifecycle; import com.arsdigita.cms.ui.BaseItemPane; import com.arsdigita.cms.ui.ContentItemPage; import com.arsdigita.cms.ui.item.ContentItemRequestLocal; +import com.arsdigita.domain.DomainObjectFactory; +import com.arsdigita.persistence.OID; import com.arsdigita.toolbox.ui.ActionGroup; import com.arsdigita.toolbox.ui.PropertyList; import com.arsdigita.toolbox.ui.Section; @@ -71,6 +74,7 @@ import com.arsdigita.xml.Element; * @author Jack Chung * @author Xixi D'Moon <xdmoon@redhat.com> * @author Justin Ross <jross@redhat.com> + * @author Jens Pelzetter jens@jp-digital.de * @version $Id: ItemLifecycleItemPane.java 1942 2009-05-29 07:53:23Z terry $ */ class ItemLifecycleItemPane extends BaseItemPane { @@ -235,14 +239,62 @@ class ItemLifecycleItemPane extends BaseItemPane { final PageState state = e.getPageState(); final ContentItem item = m_item.getContentItem(state); - republish(item, false); - if (ContentSection.getConfig().getUseStreamlinedCreation()) { + /* + * jensp 2011-12-14: Check is threaded publishing is active. If + * yes, execute publishing in a thread. + */ + if (CMSConfig.getInstance().getThreadedPublishing()) { + final Republisher republisher = new Republisher(item); + final Thread thread = new Thread(republisher); + + thread.start(); + throw new RedirectSignal( - URL.there(state.getRequest(), - Utilities.getWorkspaceURL()), true); + URL.getDispatcherPath() + + ContentItemPage.getItemURL(item, + ContentItemPage.PUBLISHING_TAB), + true); + /* + * jensp 2011-12-14 end + */ + } else { + republish(item, false); + if (ContentSection.getConfig().getUseStreamlinedCreation()) { + throw new RedirectSignal( + URL.there(state.getRequest(), + Utilities.getWorkspaceURL()), 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 Republisher(final ContentItem item) { + itemOid = item.getOID().toString(); + } + + public void run() { + final ContentItem item = (ContentItem) DomainObjectFactory. + newInstance(OID.valueOf(itemOid)); + PublishLock.getInstance().lock(item); + republish(item, false); + PublishLock.getInstance().unlock(item); + } + } } private class RepublishAndResetLink extends PublishLink { @@ -263,14 +315,62 @@ class ItemLifecycleItemPane extends BaseItemPane { final PageState state = e.getPageState(); final ContentItem item = m_item.getContentItem(state); - republish(item, true); - if (ContentSection.getConfig().getUseStreamlinedCreation()) { + /** + * jensp 2011-12-14: Execute is a thread if + * threaded publishing is active. + */ + if (CMSConfig.getInstance().getThreadedPublishing()) { + final Republisher republisher = new Republisher(item); + final Thread thread = new Thread(republisher); + + thread.start(); + throw new RedirectSignal( - URL.there(state.getRequest(), - Utilities.getWorkspaceURL()), true); + URL.getDispatcherPath() + + ContentItemPage.getItemURL(item, + ContentItemPage.PUBLISHING_TAB), + true); + } else { + /** + * jensp 2011-12-14 end + */ + republish(item, true); + if (ContentSection.getConfig().getUseStreamlinedCreation()) { + throw new RedirectSignal( + URL.there(state.getRequest(), + Utilities.getWorkspaceURL()), 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 Republisher(final ContentItem item) { + itemOid = item.getOID().toString(); + } + + public void run() { + final ContentItem item = (ContentItem) DomainObjectFactory. + newInstance(OID.valueOf(itemOid)); + PublishLock.getInstance().lock(item); + republish(item, true); + PublishLock.getInstance().unlock(item); + } + } } private class PhaseSection extends Section { @@ -298,6 +398,12 @@ class ItemLifecycleItemPane extends BaseItemPane { } } + /** + * 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, @@ -367,21 +473,53 @@ class ItemLifecycleItemPane extends BaseItemPane { String selected = (String) data.get(LIFECYCLE_ACTION); final ContentItem item = m_item.getContentItem(state); + /** + * Republish/Republish and Reset are executed in the thread + * if threaded publishing is active. + */ if (REPUBLISH.equals(selected)) { - republish(item, false); + if (CMSConfig.getInstance().getThreadedPublishing()) { + final RepublishRunner runner = new RepublishRunner(item); + final Thread thread = new Thread(runner); + + thread.start(); - if (ContentSection.getConfig().getUseStreamlinedCreation()) { throw new RedirectSignal( - URL.there(state.getRequest(), - Utilities.getWorkspaceURL()), true); + URL.getDispatcherPath() + + ContentItemPage.getItemURL(item, + ContentItemPage.PUBLISHING_TAB), + true); + } else { + republish(item, false); + + if (ContentSection.getConfig().getUseStreamlinedCreation()) { + throw new RedirectSignal( + URL.there(state.getRequest(), + Utilities.getWorkspaceURL()), true); + } } } else if (REPUBLISH_AND_RESET.equals(selected)) { - republish(item, true); + if (CMSConfig.getInstance().getThreadedPublishing()) { + final RepublishAndResetRunner runner = + new RepublishAndResetRunner( + item); + final Thread thread = new Thread(runner); + + thread.start(); - if (ContentSection.getConfig().getUseStreamlinedCreation()) { throw new RedirectSignal( - URL.there(state.getRequest(), - Utilities.getWorkspaceURL()), true); + URL.getDispatcherPath() + + ContentItemPage.getItemURL(item, + ContentItemPage.PUBLISHING_TAB), + true); + } else { + republish(item, true); + + if (ContentSection.getConfig().getUseStreamlinedCreation()) { + throw new RedirectSignal( + URL.there(state.getRequest(), + Utilities.getWorkspaceURL()), true); + } } } else if (UNPUBLISH.equals(selected)) { item.unpublish(); @@ -389,5 +527,67 @@ class ItemLifecycleItemPane extends BaseItemPane { 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 RepublishRunner(final ContentItem item) { + itemOid = item.getOID().toString(); + } + + private void doRepublish() { + final ContentItem item = (ContentItem) DomainObjectFactory. + newInstance(OID.valueOf(itemOid)); + republish(item, false); + } + + 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 RepublishAndResetRunner(final ContentItem item) { + itemOid = item.getOID().toString(); + } + + private void doRepublishAndReset() { + final ContentItem item = (ContentItem) DomainObjectFactory. + newInstance(OID.valueOf(itemOid)); + republish(item, true); + } + + 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/com/arsdigita/cms/ui/lifecycle/ItemLifecycleSelectForm.java b/ccm-cms/src/com/arsdigita/cms/ui/lifecycle/ItemLifecycleSelectForm.java index 03b8c91e0..511a4d26a 100755 --- a/ccm-cms/src/com/arsdigita/cms/ui/lifecycle/ItemLifecycleSelectForm.java +++ b/ccm-cms/src/com/arsdigita/cms/ui/lifecycle/ItemLifecycleSelectForm.java @@ -50,6 +50,7 @@ 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; @@ -61,6 +62,7 @@ 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; @@ -68,8 +70,9 @@ 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.User; -import com.arsdigita.util.Assert; +import com.arsdigita.persistence.OID; import com.arsdigita.util.UncheckedWrapperException; import com.arsdigita.web.RedirectSignal; import com.arsdigita.web.URL; @@ -85,22 +88,20 @@ import com.arsdigita.workflow.simple.WorkflowTemplate; * @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 1643 2007-09-17 14:19:06Z chrisg23 $ */ class ItemLifecycleSelectForm extends BaseForm { - private static final Logger s_log = Logger.getLogger - (ItemLifecycleSelectForm.class); - - private final static String LIFECYCLE = "lifecycle"; + 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 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; @@ -130,16 +131,17 @@ class ItemLifecycleSelectForm extends BaseForm { // Start date - m_startDate = new Date(new DateParameter(START_DATE) { - protected final Calendar getCalendar - (final HttpServletRequest sreq) { - final Calendar cal = super.getCalendar(sreq); + m_startDate = + new Date(new DateParameter(START_DATE) { - cal.setLenient(false); + protected final Calendar getCalendar(final HttpServletRequest sreq) { + final Calendar cal = super.getCalendar(sreq); - return cal; - } - }); + cal.setLenient(false); + + return cal; + } + }); addField(gz("cms.ui.item.lifecycle.start_date"), m_startDate); // Start time @@ -153,8 +155,8 @@ class ItemLifecycleSelectForm extends BaseForm { startTime.add(m_startHour); m_startHour.setSize(3); - m_startHour.addValidationListener - (new NumberInRangeValidationListener(1, 12)); + m_startHour.addValidationListener( + new NumberInRangeValidationListener(1, 12)); // Minute @@ -162,8 +164,8 @@ class ItemLifecycleSelectForm extends BaseForm { startTime.add(m_startMinute); m_startMinute.setSize(3); - m_startMinute.addValidationListener - (new NumberInRangeValidationListener(0, 59)); + m_startMinute.addValidationListener(new NumberInRangeValidationListener( + 0, 59)); // AM/PM @@ -179,16 +181,17 @@ class ItemLifecycleSelectForm extends BaseForm { // Expiration date - m_endDate = new Date(new DateParameter(END_DATE) { - protected final Calendar getCalendar - (final HttpServletRequest sreq) { - final Calendar cal = super.getCalendar(sreq); + m_endDate = + new Date(new DateParameter(END_DATE) { - cal.setLenient(false); + protected final Calendar getCalendar(final HttpServletRequest sreq) { + final Calendar cal = super.getCalendar(sreq); - return cal; - } - }); + cal.setLenient(false); + + return cal; + } + }); addField(gz("cms.ui.item.lifecycle.end_date"), m_endDate); // End time @@ -202,8 +205,8 @@ class ItemLifecycleSelectForm extends BaseForm { endTime.add(m_endHour); m_endHour.setSize(3); - m_endHour.addValidationListener - (new NumberInRangeValidationListener(1, 12)); + m_endHour.addValidationListener(new NumberInRangeValidationListener(1, + 12)); // Minute @@ -211,8 +214,8 @@ class ItemLifecycleSelectForm extends BaseForm { endTime.add(m_endMinute); m_endMinute.setSize(3); - m_endMinute.addValidationListener - (new NumberInRangeValidationListener(0, 59)); + m_endMinute.addValidationListener( + new NumberInRangeValidationListener(0, 59)); // AM/PM @@ -226,16 +229,18 @@ class ItemLifecycleSelectForm extends BaseForm { m_notificationDays = - new TextField(new IntegerParameter(NOTIFICATION_DAYS)); + new TextField(new IntegerParameter(NOTIFICATION_DAYS)); m_notificationDays.setSize(4); m_notificationHours = - new TextField(new IntegerParameter(NOTIFICATION_HOURS)); + 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(new Label(GlobalizationUtil.globalize("cms.ui.item.days"), + false)); cont.add(m_notificationHours); - cont.add(new Label(GlobalizationUtil.globalize("cms.ui.item.hours"), false)); + cont.add(new Label(GlobalizationUtil.globalize("cms.ui.item.hours"), + false)); addField(gz("cms.ui.item.notification_period"), cont); @@ -254,12 +259,13 @@ class ItemLifecycleSelectForm extends BaseForm { } private class OptionPrinter implements PrintListener { + public final void prepare(final PrintEvent e) { final ContentSection section = - CMS.getContext().getContentSection(); + CMS.getContext().getContentSection(); final LifecycleDefinitionCollection ldc = - section.getLifecycleDefinitions(); + section.getLifecycleDefinitions(); ldc.addOrder("label"); final SingleSelect target = (SingleSelect) e.getTarget(); @@ -273,9 +279,8 @@ class ItemLifecycleSelectForm extends BaseForm { // ready to be applied to an item. if (!pdc.isEmpty()) { - target.addOption - (new Option(ld.getID().toString(), - ld.getLabel())); + target.addOption(new Option(ld.getID().toString(), + ld.getLabel())); } pdc.close(); @@ -286,6 +291,7 @@ class ItemLifecycleSelectForm extends BaseForm { } private class InitListener implements FormInitListener { + public final void init(final FormSectionEvent e) { final PageState state = e.getPageState(); @@ -296,16 +302,17 @@ class ItemLifecycleSelectForm extends BaseForm { // associated lifecycle. final LifecycleDefinition ld = - item.getLifecycle().getLifecycleDefinition(); + item.getLifecycle(). + getLifecycleDefinition(); m_cycleSelect.setValue(state, ld.getID()); } else { // Set the default lifecycle (if it exists). final ContentSection section = - CMS.getContext().getContentSection(); + CMS.getContext().getContentSection(); final LifecycleDefinition ld = - ContentTypeLifecycleDefinition.getLifecycleDefinition - (section, item.getContentType()); + ContentTypeLifecycleDefinition. + getLifecycleDefinition(section, item.getContentType()); if (ld != null) { m_cycleSelect.setValue(state, ld.getID()); @@ -315,8 +322,8 @@ class ItemLifecycleSelectForm extends BaseForm { // Set the default start date. // XXX Isn't just new Date() sufficient? - final java.util.Date start = new java.util.Date - (System.currentTimeMillis()); + final java.util.Date start = new java.util.Date(System. + currentTimeMillis()); m_startDate.setValue(state, start); final Calendar calendar = Calendar.getInstance(); @@ -329,8 +336,8 @@ class ItemLifecycleSelectForm extends BaseForm { if (calendar.get(Calendar.HOUR) == 0) { m_startHour.setValue(state, new Integer(12)); } else { - m_startHour.setValue - (state, new Integer(calendar.get(Calendar.HOUR))); + m_startHour.setValue(state, new Integer(calendar.get( + Calendar.HOUR))); } final Integer min = new Integer(calendar.get(Calendar.MINUTE)); @@ -341,62 +348,288 @@ class ItemLifecycleSelectForm extends BaseForm { m_startMinute.setValue(state, min.toString()); } - m_startAmpm.setValue - (state, new Integer(calendar.get(Calendar.AM_PM))); + m_startAmpm.setValue(state, + new Integer(calendar.get(Calendar.AM_PM))); - BigInteger [] defaultTime = - BigInteger.valueOf(ContentSection. - getConfig().getDefaultNotificationTime()). - divideAndRemainder(BigInteger.valueOf(24)); + 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())); + 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 { + public final void process(final FormSectionEvent e) - throws FormProcessException { + throws FormProcessException { final PageState state = e.getPageState(); - - 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); + final Publisher publisher = new Publisher(state); + if (CMSConfig.getInstance().getThreadedPublishing()) { + final Runnable threadAction = new Runnable() { + + public void run() { + PublishLock.getInstance().lock(item); + publisher.publish(); + PublishLock.getInstance().unlock(item); + } + }; + final Thread thread = new Thread(threadAction); + thread.start(); + } else { + publisher.publish(); + } + + if (CMSConfig.getInstance().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(), + Utilities.getWorkspaceURL()), + 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); - + final LifecycleDefinition cycleDef = new LifecycleDefinition(defID); + java.util.Date startDate = - (java.util.Date) m_startDate.getValue(state); - + (java.util.Date) m_startDate.getValue(state); + final Calendar start = Calendar.getInstance(); 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.getInstance(); + + 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.getContext().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()); @@ -412,13 +645,12 @@ class ItemLifecycleSelectForm extends BaseForm { } startDate = start.getTime(); - java.util.Date endDate = - (java.util.Date) m_endDate.getValue(state); - - if (endDate != null) { + if (m_endDate.getValue(state) == null) { + endDate = null; + } else { final Calendar end = Calendar.getInstance(); - end.setTime(endDate); + 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()); @@ -439,6 +671,31 @@ class ItemLifecycleSelectForm extends BaseForm { 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.getContext().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()) { @@ -446,15 +703,19 @@ class ItemLifecycleSelectForm extends BaseForm { item.save(); } + ContentItem pending; + final LifecycleDefinition cycleDef; + final Lifecycle lifecycle; // Apply the new lifecycle. - ContentItem pending = item.publish(cycleDef, startDate); - final Lifecycle lifecycle = pending.getLifecycle(); + 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(); @@ -463,8 +724,8 @@ class ItemLifecycleSelectForm extends BaseForm { java.util.Date thisEnd = phase.getEndDate(); java.util.Date thisStart = phase.getStartDate(); if (thisStart.compareTo(endDate) > 0) { - phase.setStartDate(endDate); - phase.save(); + phase.setStartDate(endDate); + phase.save(); } if (thisEnd == null || thisEnd.compareTo(endDate) > 0) { @@ -473,38 +734,35 @@ class ItemLifecycleSelectForm extends BaseForm { } } } - + // 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); + // 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; + notificationPeriod += notificationDays.intValue() * 24; } if (notificationHours != null) { notificationPeriod += notificationHours.intValue(); } - + if (notificationPeriod > 0) { notificationDate = - computeNotificationDate(endOfCycle, notificationPeriod); + 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"); + lifecycle.addCustomPhase("expirationImminent", + new Long(notificationDate. + getTime()), + new Long(endOfCycle.getTime())); + expirationImminentPhase.setListenerClassName( + "com.arsdigita.cms.lifecycle.NotifyLifecycleListener"); expirationImminentPhase.save(); } } @@ -516,34 +774,33 @@ class ItemLifecycleSelectForm extends BaseForm { item.save(); - final Workflow workflow = m_workflow.getWorkflow(state); - try { - finish(workflow, item, Web.getContext().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); + 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 { + + static void finish(Workflow workflow, ContentItem item, User user) throws + TaskException { if (workflow != null) { final Engine engine = Engine.getInstance(CMSEngine.CMS_ENGINE_TYPE); // ; - final Iterator iter = engine.getEnabledTasks - (user, workflow.getID()).iterator(); + 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 (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); @@ -565,13 +822,14 @@ class ItemLifecycleSelectForm extends BaseForm { } private class ValidationListener implements FormValidationListener { + 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 - (lz("cms.ui.item.start_time_incomplete")); + throw new FormProcessException(lz( + "cms.ui.item.start_time_incomplete")); } Integer startMinute = (Integer) m_startMinute.getValue(state); @@ -581,13 +839,15 @@ class ItemLifecycleSelectForm extends BaseForm { Integer startAmpm = (Integer) m_startAmpm.getValue(state); - java.util.Date startDate = (java.util.Date) m_startDate.getValue(state); + java.util.Date startDate = (java.util.Date) m_startDate.getValue( + state); if (startDate == null) { - throw new FormProcessException - (lz("cms.ui.item.lifecycle.start_date_invalid")); + throw new FormProcessException(lz( + "cms.ui.item.lifecycle.start_date_invalid")); } - java.util.Date nowDate = new java.util.Date(System.currentTimeMillis()); + java.util.Date nowDate = + new java.util.Date(System.currentTimeMillis()); Calendar cStart = Calendar.getInstance(); Calendar cNow = Calendar.getInstance(); @@ -617,18 +877,18 @@ class ItemLifecycleSelectForm extends BaseForm { cStart.set(Calendar.MILLISECOND, cNow.get(Calendar.MILLISECOND)); if (cNow.after(cStart)) { - throw new FormProcessException - (lz("cms.ui.item.lifecycle.start_date_in_past")); + throw new FormProcessException(lz( + "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); + (java.util.Date) m_endDate.getValue(state); if (endHour == null && (endMinute != null || endDate != null)) { - throw new FormProcessException - (lz("cms.ui.item.lifecycle.end_time_incomplete")); + throw new FormProcessException(lz( + "cms.ui.item.lifecycle.end_time_incomplete")); } if (endMinute == null && endHour != null) { @@ -640,8 +900,8 @@ class ItemLifecycleSelectForm extends BaseForm { Integer endAmpm = (Integer) m_endAmpm.getValue(state); if (endDate == null && !timeBlank) { - throw new FormProcessException - (lz("cms.ui.item.lifecycle.end_date_invalid")); + throw new FormProcessException(lz( + "cms.ui.item.lifecycle.end_date_invalid")); } if (endDate != null) { @@ -665,25 +925,25 @@ class ItemLifecycleSelectForm extends BaseForm { // 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.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 - (lz("cms.ui.item.lifecycle.end_date_before_start_date")); - } + //check if the end date is prior to the start date + if (cStart.after(cEnd)) { + throw new FormProcessException(lz( + "cms.ui.item.lifecycle.end_date_before_start_date")); + } Integer notificationDays = - (Integer)m_notificationDays.getValue(state); + (Integer) m_notificationDays.getValue(state); Integer notificationHours = - (Integer)m_notificationHours.getValue(state); + (Integer) m_notificationHours.getValue(state); int notificationPeriod = 0; if (notificationDays != null) { - notificationPeriod += notificationDays.intValue()*24; + notificationPeriod += notificationDays.intValue() * 24; } if (notificationHours != null) { notificationPeriod += notificationHours.intValue(); @@ -692,20 +952,19 @@ class ItemLifecycleSelectForm extends BaseForm { if (notificationPeriod > 0) { // point in time for notification == end date - notificationPeriod java.util.Date notificationDate = - computeNotificationDate(cEnd.getTime(), - notificationPeriod); + 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() )) { + if (notificationDate.before(cStart.getTime())) { s_log.debug("notification date is before start date!"); - String errorMessage = (String) - GlobalizationUtil - .globalize("cms.ui.item.notification_period_before_start") - .localize(); + String errorMessage = (String) GlobalizationUtil. + globalize( + "cms.ui.item.notification_period_before_start"). + localize(); throw new FormProcessException(errorMessage); - } - else { + } else { s_log.debug("notification date is after start date, OK"); } } @@ -714,6 +973,7 @@ class ItemLifecycleSelectForm extends BaseForm { } public class TimeZonePrinter implements PrintListener { + public void prepare(PrintEvent e) { final Label target = (Label) e.getTarget(); if (ContentSection.getConfig().getHideTimezone()) { @@ -727,8 +987,9 @@ class ItemLifecycleSelectForm extends BaseForm { mStart.setTime((java.util.Date) m_startDate.getValue(state)); } - final String zone = mStart.getTimeZone().getDisplayName - (true, TimeZone.SHORT); + final String zone = + mStart.getTimeZone().getDisplayName(true, + TimeZone.SHORT); target.setLabel(zone); } @@ -749,7 +1010,7 @@ class ItemLifecycleSelectForm extends BaseForm { return null; } - return new - java.util.Date(endDate.getTime() - (long)notificationPeriod * 3600000L); + return new java.util.Date(endDate.getTime() - (long) notificationPeriod + * 3600000L); } }