From 48dea0fb14343dcf4d70a32002fae7c1a91eb540 Mon Sep 17 00:00:00 2001 From: jensp Date: Wed, 16 Nov 2016 18:37:08 +0000 Subject: [PATCH] CCM NG/ccm-core,ccm-cms: Some changes to Workflow, Task etc. Primarly some missing features/methods required by Workflow UI in CCM CMS. git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4441 8810af33-2d31-482b-a856-94f89814c4df --- .../arsdigita/cms/ui/ContentItemPage.java.off | 2 +- ...java => ContentSectionContextBar.java.off} | 0 ...nPage.java => ContentSectionPage.java.off} | 0 .../ui/authoring/AuthoringKitWizard.java.off | 36 +- .../cms/ui/authoring/WizardSelector.java.off | 99 ++-- .../ui/workflow/AssignedTaskController.java | 10 +- ...tion.java => AssignedTaskSection.java.off} | 21 +- ...kTable.java => AssignedTaskTable.java.off} | 9 +- ...=> AssignedTaskTableModelBuilder.java.off} | 0 ...aseTaskForm.java => BaseTaskForm.java.off} | 12 +- ...ane.java => BaseWorkflowItemPane.java.off} | 0 .../cms/ui/workflow/CommentAddForm.java.off | 77 +++ ...{TaskAddForm.java => TaskAddForm.java.off} | 4 +- ...{TaskAddRole.java => TaskAddRole.java.off} | 0 .../cms/ui/workflow/TaskAddUser.java | 4 +- ...askEditForm.java => TaskEditForm.java.off} | 4 +- .../cms/ui/workflow/TaskFinishForm.java.off | 253 +++++++++ ...askItemPane.java => TaskItemPane.java.off} | 4 +- ...inPane.java => WorkflowAdminPane.java.off} | 0 ...temPane.java => WorkflowItemPane.java.off} | 0 .../workflow/AuthoringTaskURLGenerator.java | 47 ++ .../cms/workflow/DeployTaskURLGenerator.java | 50 ++ .../cms/workflow/EditingTaskURLGenerator.java | 57 ++ .../cms/workflow/TaskURLGenerator.java | 34 ++ .../librecms/contentsection/ContentItem.java | 164 +++--- .../contentsection/ContentItemManager.java | 533 +++++++++--------- .../contentsection/ContentItemRepository.java | 15 + .../java/org/librecms/workflow/CmsTask.java | 15 +- .../org/librecms/workflow/CmsTaskType.java | 192 +------ .../workflow/CmsTaskTypeRepository.java | 43 -- .../workflow/TaskEventUrlGenerator.java | 156 ----- .../{UserTask.java => AssignableTask.java} | 30 +- ...ory.java => AssignableTaskRepository.java} | 41 +- .../main/java/org/libreccm/workflow/Task.java | 98 ++-- .../org/libreccm/workflow/TaskAssignment.java | 6 +- .../java/org/libreccm/workflow/Workflow.java | 109 +++- .../libreccm/workflow/WorkflowManager.java | 272 +++++---- .../libreccm/workflow/WorkflowRepository.java | 22 + .../libreccm/workflow/WorkflowTemplate.java | 8 + .../security/EqualsAndHashCodeTest.java | 8 +- .../workflow/EqualsAndHashCodeTest.java | 60 +- .../org/libreccm/workflow/ToStringTest.java | 2 +- .../scripts/create_ccm_core_schema.sql | 82 +-- .../scripts/create_ccm_core_schema.sql | 81 +-- 44 files changed, 1548 insertions(+), 1112 deletions(-) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/{ContentSectionContextBar.java => ContentSectionContextBar.java.off} (100%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/{ContentSectionPage.java => ContentSectionPage.java.off} (100%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/{AssignedTaskSection.java => AssignedTaskSection.java.off} (92%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/{AssignedTaskTable.java => AssignedTaskTable.java.off} (94%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/{AssignedTaskTableModelBuilder.java => AssignedTaskTableModelBuilder.java.off} (100%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/{BaseTaskForm.java => BaseTaskForm.java.off} (95%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/{BaseWorkflowItemPane.java => BaseWorkflowItemPane.java.off} (100%) create mode 100755 ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/CommentAddForm.java.off rename ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/{TaskAddForm.java => TaskAddForm.java.off} (97%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/{TaskAddRole.java => TaskAddRole.java.off} (100%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/{TaskEditForm.java => TaskEditForm.java.off} (97%) create mode 100755 ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskFinishForm.java.off rename ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/{TaskItemPane.java => TaskItemPane.java.off} (99%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/{WorkflowAdminPane.java => WorkflowAdminPane.java.off} (100%) rename ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/{WorkflowItemPane.java => WorkflowItemPane.java.off} (100%) create mode 100755 ccm-cms/src/main/java/com/arsdigita/cms/workflow/AuthoringTaskURLGenerator.java create mode 100755 ccm-cms/src/main/java/com/arsdigita/cms/workflow/DeployTaskURLGenerator.java create mode 100755 ccm-cms/src/main/java/com/arsdigita/cms/workflow/EditingTaskURLGenerator.java create mode 100755 ccm-cms/src/main/java/com/arsdigita/cms/workflow/TaskURLGenerator.java delete mode 100644 ccm-cms/src/main/java/org/librecms/workflow/CmsTaskTypeRepository.java delete mode 100644 ccm-cms/src/main/java/org/librecms/workflow/TaskEventUrlGenerator.java rename ccm-core/src/main/java/org/libreccm/workflow/{UserTask.java => AssignableTask.java} (89%) rename ccm-core/src/main/java/org/libreccm/workflow/{UserTaskRepository.java => AssignableTaskRepository.java} (61%) diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/ContentItemPage.java.off b/ccm-cms/src/main/java/com/arsdigita/cms/ui/ContentItemPage.java.off index 2d39a421f..686887a3e 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/ContentItemPage.java.off +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/ContentItemPage.java.off @@ -436,7 +436,7 @@ public class ContentItemPage extends CMSPage implements ActionListener { * @param itemId the id of the ContentItem object to display * @param tab The index of the tab to display */ - public static String getItemURL(BigDecimal itemId, int tab) { + public static String getItemURL(long itemId, int tab) { final ContentItem item = (ContentItem) DomainObjectFactory.newInstance(new OID( ContentItem.BASE_DATA_OBJECT_TYPE, itemId)); 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.off similarity index 100% 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.off 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.off 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.off diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/AuthoringKitWizard.java.off b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/AuthoringKitWizard.java.off index 0424c008f..ad268f1fb 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/AuthoringKitWizard.java.off +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/AuthoringKitWizard.java.off @@ -57,7 +57,7 @@ import com.arsdigita.toolbox.ui.Section; import com.arsdigita.util.Assert; import com.arsdigita.util.SequentialMap; import com.arsdigita.util.UncheckedWrapperException; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; @@ -66,6 +66,9 @@ import java.util.Collection; import java.util.Iterator; import java.util.ArrayList; import java.util.Collections; +import org.apache.logging.log4j.LogManager; +import org.librecms.contenttypes.AuthoringKitInfo; +import org.librecms.contenttypes.ContentTypeInfo; /** * This class represents a single authoring kit. The wizard accepts a @@ -83,12 +86,11 @@ import java.util.Collections; * This constructor will be called when the component is automatically * instantiated by the AuthoringKitWizard.

* - * @version $Id: AuthoringKitWizard.java 2140 2011-01-16 12:04:20Z pboy $ */ public class AuthoringKitWizard extends LayoutPanel implements Resettable { /** Private Logger instance for this class */ - private static final Logger s_log = Logger.getLogger( + private static final Logger LOGGER = LogManager.getLogger( AuthoringKitWizard.class); private static Class[] s_args = new Class[]{ ItemSelectionModel.class, @@ -103,8 +105,8 @@ public class AuthoringKitWizard extends LayoutPanel implements Resettable { private static final java.util.List s_assets = new ArrayList(); private final Object[] m_vals; - private final ContentType m_type; - private final AuthoringKit m_kit; + private final ContentTypeInfo m_type; + private final AuthoringKitInfo m_kit; private final ItemSelectionModel m_sel; private final WorkflowRequestLocal m_workflow; private final AssignedTaskTable m_tasks; @@ -131,14 +133,12 @@ public class AuthoringKitWizard extends LayoutPanel implements Resettable { * * @param type The content type of the items that this wizard will * handle - * - * @param itemModel The item selection model which will supply - * this wizard with the content item object + * @param model */ - public AuthoringKitWizard(final ContentType type, + public AuthoringKitWizard(final ContentTypeInfo type, final ItemSelectionModel model) { - if (s_log.isDebugEnabled()) { - s_log.debug("Authoring kit wizard for type " + type + " " + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Authoring kit wizard for type " + type + " " + "undergoing creation"); } @@ -262,9 +262,9 @@ public class AuthoringKitWizard extends LayoutPanel implements Resettable { Collection skipSteps = ContentSection.getConfig().getAssetStepsToSkip( type); Iterator it = skipSteps.iterator(); - if (s_log.isDebugEnabled()) { + if (LOGGER.isDebugEnabled()) { while (it.hasNext()) { - s_log.debug("skip step " + it.next()); + LOGGER.debug("skip step " + it.next()); } } //Iterator assets = s_assets.iterator(); @@ -276,7 +276,7 @@ public class AuthoringKitWizard extends LayoutPanel implements Resettable { final String baseObjectType = data.getBaseDataObjectType(); //Class step = (Class) data[1]; Class step = data.getStep(); - s_log.debug("possibly adding asset step " + step.getName()); + LOGGER.debug("possibly adding asset step " + step.getName()); if (!skipSteps.contains(step.getName())) { //GlobalizedMessage label = (GlobalizedMessage) data[2]; GlobalizedMessage label = data.getLabel(); @@ -423,7 +423,7 @@ public class AuthoringKitWizard extends LayoutPanel implements Resettable { // registered, but I needed the image step to use a different step class if the specialised // image step application was loaded. Solution is to ensure initialiser in new project // runs after original ccm-ldn-image-step initializer and override the registered step here - s_log.debug( + LOGGER.debug( "registering asset step - label: " + label.localize() + " step class: " @@ -451,7 +451,7 @@ public class AuthoringKitWizard extends LayoutPanel implements Resettable { */ if ((thisObjectType.equals(baseObjectType)) && (thisLabel.localize().equals(label.localize()))) { - s_log.debug( + LOGGER.debug( "registering authoring step with same label as previously registered step"); s_assets.remove(data); break; @@ -570,8 +570,8 @@ public class AuthoringKitWizard extends LayoutPanel implements Resettable { * @param className The Java class name of the step */ protected Component instantiateStep(String name) { - if (s_log.isDebugEnabled()) { - s_log.debug("Instantiating kit wizard '" + name + "' with " + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Instantiating kit wizard '" + name + "' with " + "arguments " + s_args); } diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/WizardSelector.java.off b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/WizardSelector.java.off index 64d0db1ef..9754fa27d 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/WizardSelector.java.off +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/WizardSelector.java.off @@ -18,7 +18,6 @@ */ package com.arsdigita.cms.ui.authoring; - import com.arsdigita.bebop.Component; import com.arsdigita.bebop.PageState; import com.arsdigita.bebop.Resettable; @@ -33,6 +32,7 @@ import org.librecms.contentsection.ContentType; import com.arsdigita.cms.ItemSelectionModel; import com.arsdigita.toolbox.ui.LayoutPanel; +import com.arsdigita.util.UncheckedWrapperException; import com.arsdigita.xml.Element; import oracle.jrockit.jfr.events.ContentTypeImpl; @@ -42,37 +42,36 @@ import org.librecms.contenttypes.ContentTypeInfo; import java.math.BigDecimal; - /** - * An invisible component which contains all the possible authoring kits. - * The kits are loaded from the database at construction time. The selector - * chooses which kit to display at page rendering time based on the value - * of the content_type state parameter. - * - * Essentially, this component is a hack which is used to get around - * the fact that we cannot instantiate stateful components dynamically. + * An invisible component which contains all the possible authoring kits. The + * kits are loaded from the database at construction time. The selector chooses + * which kit to display at page rendering time based on the value of the + * content_type state parameter. + * + * Essentially, this component is a hack which is used to get around the fact + * that we cannot instantiate stateful components dynamically. * * @author Jens Pelzetter * @author unknown */ public class WizardSelector extends AuthoringKitSelector - implements Resettable { + implements Resettable { private ItemSelectionModel itemSelectionModel; /** - * Construct a new WizardSelector. Load all the possible authoring kits - * from the database and construct wizards for them. + * Construct a new WizardSelector. Load all the possible authoring kits from + * the database and construct wizards for them. * - * @param model the {@link ItemSelectionModel} which will - * supply the wizard with its item + * @param model the {@link ItemSelectionModel} which will supply the wizard + * with its item * - * @param typeModel the {@link ACSObjectSelectionModel} which will - * supply the default content type + * @param typeModel the {@link ACSObjectSelectionModel} which will supply + * the default content type * * @pre itemModel != null */ - public WizardSelector(final ItemSelectionModel model, + public WizardSelector(final ItemSelectionModel model, final SingleSelectionModel typeModel) { super(typeModel); itemSelectionModel = model; @@ -81,18 +80,19 @@ public class WizardSelector extends AuthoringKitSelector /** * Get the wizard for the given kit. + * * @param kit * @param type - * @return + * @return */ - public Component instantiateKitComponent(final AuthoringKitInfo kit, + @Override + public Component instantiateKitComponent(final AuthoringKitInfo kit, final ContentTypeInfo type) { - final ItemSelectionModel itemModel = new - ItemSelectionModel(type, - (LongParameter)itemSelectionModel.getStateParameter()); + final ItemSelectionModel itemModel = new ItemSelectionModel( + type, (LongParameter) itemSelectionModel.getStateParameter()); - final AuthoringKitWizard wizard = new AuthoringKitWizard(type, itemModel); + final AuthoringKitWizard wizard = new AuthoringKitWizard(type, itemModel); return wizard; } @@ -107,54 +107,51 @@ public class WizardSelector extends AuthoringKitSelector private Component getCurrentWizard(PageState state) { // Get the current item and extract its content type - if(!itemSelectionModel.isSelected(state)) - throw new RuntimeException( (String) GlobalizationUtil.globalize( - "cms.ui.authoring.missing_item_id") - .localize()); + if (!itemSelectionModel.isSelected(state)) { + throw new UncheckedWrapperException("No item selected."); + } - ContentItem item = - (ContentItem)itemSelectionModel.getSelectedObject(state); + final ContentItem item = (ContentItem) itemSelectionModel + .getSelectedObject(state); - ContentType type = item.getContentType(); - BigDecimal typeId; + final ContentType type = item.getContentType(); + final String typeClass; - if(type == null) { + if (type == null) { // Try to get the default content type - typeId = (BigDecimal)getComponentSelectionModel().getSelectedKey(state); - if(typeId == null) { - throw new RuntimeException((String) GlobalizationUtil.globalize( - "cms.ui.authoring.missing_content_type") - .localize()); + typeClass = getComponentSelectionModel().getSelectedKey(state); + if (typeClass == null || typeClass.isEmpty()) { + throw new UncheckedWrapperException("Content type is missing"); } } else { - typeId = type.getID(); + typeClass = type.getContentItemClass(); } - + // Return the selected wizard - return (Component)getComponent(typeId); + return (Component) getComponent(typeClass); } // Choose the right wizard and run it - public void generateXML(PageState state, Element parent) { + @Override + public void generateXML(final PageState state, final Element parent) { - Component c = getCurrentWizard(state); + final Component component = getCurrentWizard(state); - if(c == null) { - throw new RuntimeException( (String) GlobalizationUtil.globalize( - "cms.ui.authoring.no_current_wizard") - .localize()); + if (component == null) { + throw new UncheckedWrapperException("No Wizard."); } - c.generateXML(state, parent); + component.generateXML(state, parent); } /** * Reset the state of the current wizard */ - public void reset(PageState state) { - Resettable r = (Resettable)getCurrentWizard(state); - if(r != null) r.reset(state); + public void reset(final PageState state) { + final Resettable resettable = (Resettable) getCurrentWizard(state); + if (resettable != null) { + resettable.reset(state); + } } - } diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/AssignedTaskController.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/AssignedTaskController.java index 25f60747f..ae40c2e3f 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/AssignedTaskController.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/AssignedTaskController.java @@ -24,8 +24,8 @@ import com.arsdigita.kernel.KernelConfig; import org.libreccm.configuration.ConfigurationManager; import org.libreccm.security.Shiro; import org.libreccm.security.User; -import org.libreccm.workflow.UserTask; -import org.libreccm.workflow.UserTaskRepository; +import org.libreccm.workflow.AssignableTask; +import org.libreccm.workflow.AssignableTaskRepository; import org.libreccm.workflow.Workflow; import org.libreccm.workflow.WorkflowManager; @@ -50,7 +50,7 @@ public class AssignedTaskController { private WorkflowManager workflowManager; @Inject - private UserTaskRepository userTaskRepo; + private AssignableTaskRepository userTaskRepo; @Inject private Shiro shiro; @@ -71,7 +71,7 @@ public class AssignedTaskController { @Transactional(Transactional.TxType.REQUIRED) public List> getAssignedTasks(final Workflow workflow) { final User user = shiro.getUser(); - final List tasks = userTaskRepo.getAssignedTasks(user, + final List tasks = userTaskRepo.getAssignedTasks(user, workflow); return tasks @@ -81,7 +81,7 @@ public class AssignedTaskController { } - private RowData createRowData(final UserTask task) { + private RowData createRowData(final AssignableTask task) { final RowData rowData = new RowData<>(3); diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/AssignedTaskSection.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/AssignedTaskSection.java.off similarity index 92% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/AssignedTaskSection.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/AssignedTaskSection.java.off index 3ffe736ef..16d84091c 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/AssignedTaskSection.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/AssignedTaskSection.java.off @@ -39,14 +39,14 @@ import org.apache.log4j.Logger; import org.libreccm.cdi.utils.CdiUtil; import org.libreccm.security.Shiro; import org.libreccm.workflow.Task; -import org.libreccm.workflow.UserTask; -import org.libreccm.workflow.UserTaskRepository; +import org.libreccm.workflow.AssignableTask; +import org.libreccm.workflow.AssignableTaskRepository; import org.libreccm.workflow.WorkflowConstants; import org.libreccm.workflow.WorkflowManager; import org.libreccm.workflow.WorkflowRepository; import org.librecms.CmsConstants; import org.librecms.workflow.CmsTask; -import org.librecms.workflow.CmsTaskType; +import org.librecms.workflow.CmsTaskTypeOld; import java.util.List; @@ -177,16 +177,15 @@ public final class AssignedTaskSection extends Section { protected final Object initialValue(final PageState state) { final Workflow workflow = m_flow.getWorkflow(state); final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); - final UserTaskRepository userTaskRepo = cdiUtil.findBean( - UserTaskRepository.class); + final AssignableTaskRepository userTaskRepo = cdiUtil.findBean(AssignableTaskRepository.class); final Shiro shiro = cdiUtil.findBean(Shiro.class); return userTaskRepo.findEnabledTasksForWorkflow(shiro.getUser(), workflow); } @SuppressWarnings("unchecked") - final List getTasks(final PageState state) { - return (ArrayList) get(state); + final List getTasks(final PageState state) { + return (ArrayList) get(state); } } @@ -208,7 +207,7 @@ public final class AssignedTaskSection extends Section { final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); final WorkflowManager workflowManager = cdiUtil.findBean(WorkflowManager.class); - for(final UserTask task : m_tasks.getTasks(state)) { + for(final AssignableTask task : m_tasks.getTasks(state)) { if (relevant(task) && !task.isLocked()) { workflowManager.lockTask(task); } @@ -219,7 +218,7 @@ public final class AssignedTaskSection extends Section { final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); final WorkflowManager workflowManager = cdiUtil.findBean(WorkflowManager.class); - for(final UserTask task : m_tasks.getTasks(state)) { + for(final AssignableTask task : m_tasks.getTasks(state)) { if (relevant(task) && task.isLocked()) { workflowManager.unlockTask(task); } @@ -227,7 +226,7 @@ public final class AssignedTaskSection extends Section { } final boolean tasksLocked(final PageState state) { - for(final UserTask task : m_tasks.getTasks(state)) { + for(final AssignableTask task : m_tasks.getTasks(state)) { if (relevant(task) && !task.isLocked()) { return false; } @@ -248,7 +247,7 @@ public final class AssignedTaskSection extends Section { return !m_tasks.getTasks(state).isEmpty(); } - private boolean relevant(final UserTask task) { + private boolean relevant(final AssignableTask task) { return true; // ToDo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/AssignedTaskTable.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/AssignedTaskTable.java.off similarity index 94% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/AssignedTaskTable.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/AssignedTaskTable.java.off index 848793dbc..bc39534f4 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/AssignedTaskTable.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/AssignedTaskTable.java.off @@ -40,8 +40,8 @@ import org.apache.log4j.Logger; import org.libreccm.cdi.utils.CdiUtil; import org.libreccm.security.Shiro; import org.libreccm.security.User; -import org.libreccm.workflow.UserTask; -import org.libreccm.workflow.UserTaskRepository; +import org.libreccm.workflow.AssignableTask; +import org.libreccm.workflow.AssignableTaskRepository; import org.libreccm.workflow.WorkflowManager; import org.librecms.CmsConstants; import org.librecms.workflow.CmsTaskTypeRepository; @@ -70,13 +70,12 @@ public final class AssignedTaskTable extends Table { final int column = event.getColumn(); final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); - final UserTaskRepository userTaskRepo = cdiUtil.findBean( - UserTaskRepository.class); + final AssignableTaskRepository userTaskRepo = cdiUtil.findBean(AssignableTaskRepository.class); final WorkflowManager workflowManager = cdiUtil.findBean(WorkflowManager.class); final Shiro shiro = cdiUtil.findBean(Shiro.class); if (column == 1) { - final UserTask task = userTaskRepo.findById((Long) event + final AssignableTask task = userTaskRepo.findById((Long) event .getRowKey()); final User currentUser = shiro.getUser(); final User lockingUser = task.getLockingUser(); diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/AssignedTaskTableModelBuilder.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/AssignedTaskTableModelBuilder.java.off similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/AssignedTaskTableModelBuilder.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/AssignedTaskTableModelBuilder.java.off diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/BaseTaskForm.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/BaseTaskForm.java.off similarity index 95% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/BaseTaskForm.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/BaseTaskForm.java.off index aa4583994..9ff3c3b5e 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/BaseTaskForm.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/BaseTaskForm.java.off @@ -27,7 +27,7 @@ import com.arsdigita.bebop.parameters.IntegerParameter; import com.arsdigita.cms.ui.BaseForm; import com.arsdigita.cms.ui.ListOptionPrintListener; -import org.librecms.workflow.CmsTaskType; +import org.librecms.workflow.CmsTaskTypeOld; import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.kernel.KernelConfig; @@ -142,27 +142,27 @@ class BaseTaskForm extends BaseForm { } */ // Fix this one too - private class TaskTypePrintListener extends ListOptionPrintListener { + private class TaskTypePrintListener extends ListOptionPrintListener { @Override - protected List getDataQuery(final PageState state) { + protected List getDataQuery(final PageState state) { final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); final CmsTaskTypeRepository taskTypeRepo = cdiUtil.findBean( CmsTaskTypeRepository.class); - final List taskTypes = taskTypeRepo.findAll(); + final List taskTypes = taskTypeRepo.findAll(); return taskTypes; } @Override - public String getKey(final CmsTaskType taskType) { + public String getKey(final CmsTaskTypeOld taskType) { return Long.toString(taskType.getTaskTypeId()); } @Override - public String getValue(final CmsTaskType taskType) { + public String getValue(final CmsTaskTypeOld taskType) { final KernelConfig kernelConfig = KernelConfig.getConfig(); final Locale defaultLocale = kernelConfig.getDefaultLocale(); return taskType.getName().getValue(defaultLocale); 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.off similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/BaseWorkflowItemPane.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/BaseWorkflowItemPane.java.off diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/CommentAddForm.java.off b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/CommentAddForm.java.off new file mode 100755 index 000000000..64f91fdf7 --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/CommentAddForm.java.off @@ -0,0 +1,77 @@ +/* + * 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.workflow; + +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.event.FormProcessListener; +import com.arsdigita.bebop.event.FormSectionEvent; +import com.arsdigita.bebop.form.TextArea; +import com.arsdigita.cms.ui.BaseForm; +import org.librecms.workflow.CmsTask; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.workflow.TaskRepository; + +/** + * @author Justin Ross + * @author Jens Pelzetter + */ +class CommentAddForm extends BaseForm { + + private static final Logger LOGGER = LogManager.getLogger(CommentAddForm.class); + + private final TaskRequestLocal selectedTask; + private final TextArea comment; + + public CommentAddForm(final TaskRequestLocal task) { + super("addComment", gz("cms.ui.workflow.task.comment.add")); + + this.selectedTask = task; + + comment = new TextArea("Comment"); + comment.setWrap(TextArea.SOFT); + comment.setRows(5); + comment.setCols(40); + + addComponent(comment); + + addAction(new Finish()); + addAction(new Cancel()); + + addProcessListener(new ProcessListener()); + } + + private class ProcessListener implements FormProcessListener { + @Override + public final void process(final FormSectionEvent event) + throws FormProcessException { + LOGGER.debug("Processing comment add"); + + final PageState state = event.getPageState(); + final CmsTask task = selectedTask.getTask(state); + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final TaskRepository taskRepo = cdiUtil.findBean(TaskRepository.class); + + task.addComment((String)comment.getValue(state)); + taskRepo.save(task); + } + } +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskAddForm.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskAddForm.java.off similarity index 97% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskAddForm.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskAddForm.java.off index 0a141a20c..aa0e63d80 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskAddForm.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskAddForm.java.off @@ -30,7 +30,7 @@ import com.arsdigita.bebop.form.OptionGroup; import com.arsdigita.kernel.KernelConfig; import org.librecms.workflow.CmsTask; -import org.librecms.workflow.CmsTaskType; +import org.librecms.workflow.CmsTaskTypeOld; import com.arsdigita.util.UncheckedWrapperException; @@ -120,7 +120,7 @@ class TaskAddForm extends BaseTaskForm { defaultLocale, ((String) m_description.getValue(state))); - final CmsTaskType taskType = taskTypeRepo.findById((Long) m_type.getValue(state)); + final CmsTaskTypeOld taskType = taskTypeRepo.findById((Long) m_type.getValue(state)); task.setTaskType(taskType); task.setActive(true); diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskAddRole.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskAddRole.java.off similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskAddRole.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskAddRole.java.off diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskAddUser.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskAddUser.java index a670a6417..e5f4aa720 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskAddUser.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskAddUser.java @@ -30,7 +30,7 @@ import com.arsdigita.cms.ui.UserSearchForm; import com.arsdigita.globalization.GlobalizedMessage; import org.libreccm.security.User; -import org.libreccm.workflow.UserTask; +import org.libreccm.workflow.AssignableTask; import com.arsdigita.xml.Element; @@ -146,7 +146,7 @@ class TaskAddUser extends SimpleContainer { WorkflowManager.class); final UserRepository userRepo = cdiUtil.findBean(UserRepository.class); - final UserTask task = m_task.getTask(state); + final AssignableTask task = m_task.getTask(state); User user; for (int i = 0; i < users.length; i++) { diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskEditForm.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskEditForm.java.off similarity index 97% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskEditForm.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskEditForm.java.off index 1816b6e04..3e4bbc3fd 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskEditForm.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskEditForm.java.off @@ -37,7 +37,7 @@ import org.libreccm.cdi.utils.CdiUtil; import org.libreccm.configuration.ConfigurationManager; import org.libreccm.workflow.Task; import org.libreccm.workflow.TaskRepository; -import org.librecms.workflow.CmsTaskType; +import org.librecms.workflow.CmsTaskTypeOld; import org.librecms.workflow.CmsTaskTypeRepository; import java.util.ArrayList; @@ -144,7 +144,7 @@ class TaskEditForm extends BaseTaskForm { defaultLocale, (String) m_description.getValue(state)); - final CmsTaskType taskType = taskTypeRepo.findById((Long) m_type + final CmsTaskTypeOld taskType = taskTypeRepo.findById((Long) m_type .getValue(state)); task.setTaskType(taskType); diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskFinishForm.java.off b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskFinishForm.java.off new file mode 100755 index 000000000..525bdcc29 --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskFinishForm.java.off @@ -0,0 +1,253 @@ +/* + * 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.workflow; + +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +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.form.Option; +import com.arsdigita.bebop.form.RadioGroup; +import com.arsdigita.bebop.parameters.BooleanParameter; + +import org.librecms.contentsection.ContentSection; + +import com.arsdigita.cms.ContentCenter; +import com.arsdigita.cms.ui.ContentItemPage; +import com.arsdigita.globalization.GlobalizedMessage; +import com.arsdigita.util.UncheckedWrapperException; + +import org.librecms.workflow.CmsTask; +import org.librecms.workflow.CmsTaskTypeOld; + +import com.arsdigita.web.RedirectSignal; +import com.arsdigita.web.URL; +import com.arsdigita.web.Web; + +import org.libreccm.workflow.Task; +import org.apache.logging.log4j.Logger; + +import java.util.Iterator; +import java.util.Optional; + +import org.apache.logging.log4j.LogManager; +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.security.PermissionChecker; +import org.libreccm.security.Shiro; +import org.libreccm.workflow.TaskRepository; +import org.libreccm.workflow.WorkflowManager; +import org.libreccm.workflow.WorkflowRepository; +import org.librecms.CmsConstants; +import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.ContentItemRepository; + +/** + *

+ * A form that prompts the user to comment on and approve tasks and then + * finishes the task if it was approved.

+ * + * @author Justin Ross <jross@redhat.com> + * @author Jens Pelzetter + */ +public final class TaskFinishForm extends CommentAddForm { + + private static final Logger LOGGER = LogManager.getLogger( + TaskFinishForm.class); + private final TaskRequestLocal m_task; + private final Label m_approvePrompt; + private final RadioGroup m_approve; + + public TaskFinishForm(final TaskRequestLocal task) { + super(task); + + m_task = task; + + m_approve = new RadioGroup(new BooleanParameter("approve")); + m_approve.addOption(new Option("true", + lz("cms.ui.workflow.task.approve"))); + m_approve.addOption(new Option("false", + lz("cms.ui.workflow.task.reject"))); + + m_approvePrompt = new Label(gz("cms.ui.workflow.task.approve_prompt")); + + addComponent(m_approvePrompt); + addComponent(m_approve); + + addInitListener(new InitListener()); + addValidationListener(new ValidationListener()); + addProcessListener(new ProcessListener()); + } + + private class InitListener implements FormInitListener { + + @Override + public final void init(final FormSectionEvent e) { + LOGGER.debug("Initializing task finish"); + + final PageState state = e.getPageState(); + + if (isVisible(state)) { + final CmsTask task = m_task.getTask(state); + + if (requiresApproval(task)) { + m_approvePrompt.setVisible(state, true); + m_approve.setVisible(state, true); + } else { + m_approvePrompt.setVisible(state, false); + m_approve.setVisible(state, false); + } + } + } + } + + private class ValidationListener implements FormValidationListener { + + @Override + public final void validate(final FormSectionEvent e) + throws FormProcessException { + LOGGER.debug("Validating task finish"); + + final PageState state = e.getPageState(); + final CmsTask task = m_task.getTask(state); + + if (requiresApproval(task) && m_approve.getValue(state) == null) { + throw new FormProcessException(new GlobalizedMessage( + "cms.ui.workflow.task.approval_or_reject_required", + CmsConstants.CMS_BUNDLE)); + } + } + } + + private class ProcessListener implements FormProcessListener { + + @Override + public final void process(final FormSectionEvent event) + throws FormProcessException { + LOGGER.debug("Processing task finish"); + + final PageState state = event.getPageState(); + final CmsTask task = m_task.getTask(state); + boolean finishedTask = false; + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final PermissionChecker permissionChecker = cdiUtil.findBean( + PermissionChecker.class); + final ContentItemRepository itemRepo = cdiUtil.findBean( + ContentItemRepository.class); + final Optional item = itemRepo.findItemWithWorkflow( + task.getWorkflow()); + + if (!item.isPresent()) { + throw new UncheckedWrapperException( + "Workflow not assigned to an item"); + } + + permissionChecker.checkPermission(task.getTaskType().getPrivilege(), + item.get()); + + final TaskRepository taskRepo = cdiUtil.findBean( + TaskRepository.class); + + if (requiresApproval(task)) { + LOGGER.debug("The task requires approval; checking to see " + + "if it's approved"); + + // XXX I think the fact that this returns a Boolean is + // the effect of broken parameter marshalling in + // Bebop. + final Boolean isApproved = (Boolean) m_approve.getValue(state); + + if (isApproved.equals(Boolean.TRUE)) { + LOGGER.debug("The task is approved; finishing the task"); + + final Shiro shiro = cdiUtil.findBean(Shiro.class); + final WorkflowManager workflowManager = cdiUtil.findBean( + WorkflowManager.class); + + task.setActive(false); + finishedTask = true; + } else { + LOGGER.debug("The task is rejected; reenabling dependent " + + "tasks"); + + // Reenable the previous tasks. + final Iterator iter = task.getDependentTasks(). + iterator(); + + while (iter.hasNext()) { + final Task dependent = (Task) iter.next(); + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Reenabling task " + dependent. + getLabel()); + } + + dependent.setActive(true); + + taskRepo.save(dependent); + } + } + } else { + LOGGER.debug("The task does not require approval; finishing " + + "it"); + + task.setActive(false); + taskRepo.save(task); + } + if (finishedTask) { + Iterator tasks = Engine.getInstance(CMSEngine.CMS_ENGINE_TYPE). + getEnabledTasks(Web.getWebContext().getUser(), + task.getParentID()).iterator(); + if (tasks.hasNext()) { + CmsTask thisTask = (CmsTask) tasks.next(); + PermissionDescriptor thisTaskAccess = new PermissionDescriptor( + thisTask.getTaskType().getPrivilege(), task. + getWorkflow().getObject(), user); + if (PermissionService.checkPermission(thisTaskAccess)) { + + // Lock task for user + thisTask.lock((User) user); + int targetTab = (thisTask.getTaskType().getID().equals(CmsTaskTypeOld.DEPLOY)) ? ContentItemPage.PUBLISHING_TAB : ContentItemPage.AUTHORING_TAB; + throw new RedirectSignal(URL.there(state.getRequest(), + ContentItemPage. + getItemURL( + task. + getItem(), + targetTab)), + true); + } + } + // redirect to /content-center if streamlined creation mode is active. + if (ContentSection.getConfig().getUseStreamlinedCreation()) { + throw new RedirectSignal(URL.there(state.getRequest(), + ContentCenter.getURL()), + true); + } + + } + } + } + + private static boolean requiresApproval(final CmsTask task) { + return !task.getTaskType().getID().equals(CmsTaskTypeOld.AUTHOR); + } +} 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.off similarity index 99% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskItemPane.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/TaskItemPane.java.off index b63b933c5..0ff7964a7 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.off @@ -49,7 +49,7 @@ import org.libreccm.security.Role; import org.libreccm.security.RoleRepository; import org.libreccm.security.Shiro; import org.libreccm.workflow.Task; -import org.libreccm.workflow.UserTask; +import org.libreccm.workflow.AssignableTask; import org.libreccm.workflow.WorkflowManager; import org.librecms.CmsConstants; import org.librecms.contentsection.privileges.AdminPrivileges; @@ -173,7 +173,7 @@ final class TaskItemPane extends BaseItemPane { final User user = shiro.getUser(); - final List tasks = workflowManager.lockedBy(user); + final List tasks = workflowManager.lockedBy(user); return tasks.contains(task); } diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/WorkflowAdminPane.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/WorkflowAdminPane.java.off similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/WorkflowAdminPane.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/WorkflowAdminPane.java.off diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/WorkflowItemPane.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/WorkflowItemPane.java.off similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/WorkflowItemPane.java rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/workflow/WorkflowItemPane.java.off diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/workflow/AuthoringTaskURLGenerator.java b/ccm-cms/src/main/java/com/arsdigita/cms/workflow/AuthoringTaskURLGenerator.java new file mode 100755 index 000000000..47fc0d164 --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/workflow/AuthoringTaskURLGenerator.java @@ -0,0 +1,47 @@ +/* + * 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.workflow; + +/** + * Class for generating a URL to the Authoring kit given the ID of the + * ContentItem and the Task. + * + * @author Uday Mathur (umathur@arsdigita.com) + * @author Jens Pelzetter + * */ + +public class AuthoringTaskURLGenerator implements TaskURLGenerator { + + public AuthoringTaskURLGenerator() {} + + /** + * Generates a Link to the Authoring Kit in the Item Management part + * of the CMS UI. + * + * @param itemId id of the item in question + * @param taskId this param is ignored. + * @return + * */ + @Override + public String generateURL(final long itemId, final long taskId) { + throw new UnsupportedOperationException("ToDo"); +// return ContentItemPage.getItemURL(itemId, +// ContentItemPage.AUTHORING_TAB); + } +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/workflow/DeployTaskURLGenerator.java b/ccm-cms/src/main/java/com/arsdigita/cms/workflow/DeployTaskURLGenerator.java new file mode 100755 index 000000000..ef61633d3 --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/workflow/DeployTaskURLGenerator.java @@ -0,0 +1,50 @@ +/* + * 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.workflow; + +/** + * Generates a Link to the Deploy Task Panel under the Workflow Tab in the Item + * Management part of the CMS UI. + * + * @author Uday Mathur (umathur@arsdigita.com) + * @author Jens Pelzetter + * + */ +public class DeployTaskURLGenerator implements TaskURLGenerator { + + public DeployTaskURLGenerator() { + } + + /** + * Generates a Link to the Finish Task Panel under the Workflow Tab in the + * Item Management part of the CMS UI. + * + * @param itemId id of the item in question + * @param taskId id of the task to finish + * @return + * + */ + @Override + public String generateURL(final long itemId, final long taskId) { +// String url = ContentItemPage.getItemURL(itemId, ContentItemPage.PUBLISHING_TAB); +// return url; + throw new UnsupportedOperationException("ToDo"); + } + +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/workflow/EditingTaskURLGenerator.java b/ccm-cms/src/main/java/com/arsdigita/cms/workflow/EditingTaskURLGenerator.java new file mode 100755 index 000000000..313b67710 --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/workflow/EditingTaskURLGenerator.java @@ -0,0 +1,57 @@ +/* + * 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.workflow; + +/** + * Class for generating a URL to the Authoring kit given the ID of the + * ContentItem and the Task. Eventually we may have a separate kit for editors, + * hence this is a separate class and has its own TaskType + * + * @author Uday Mathur (umathur@arsdigita.com) + * @author Jens Pelzetter + * + */ +public class EditingTaskURLGenerator implements TaskURLGenerator { + + public EditingTaskURLGenerator() { + } + + /** + * Generates a Link to the Workflow Tab in the Item Management part of the + * CMS UI. + * + * @param itemId id of the item in question + * @param taskId this param is ignored. + * + * @return + * + */ + @Override + public String generateURL(final long itemId, final long taskId) { +// final StringBuffer url = new StringBuffer +// (ContentItemPage.getItemURL(itemId, ContentItemPage.WORKFLOW_TAB)); +// +// // XXX task, approve, and action were constants; restore them +// url.append("&action=approve&task=").append(taskId.toString()); +// +// return url.toString(); + throw new UnsupportedOperationException("ToDo"); + } + +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/workflow/TaskURLGenerator.java b/ccm-cms/src/main/java/com/arsdigita/cms/workflow/TaskURLGenerator.java new file mode 100755 index 000000000..2772e4d0d --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/workflow/TaskURLGenerator.java @@ -0,0 +1,34 @@ +/* + * 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.workflow; + +import java.math.BigDecimal; + +/** + * Interface for generating a URL for a Task given the ID of the + * ContentItem and the Task. + * + * @author Uday Mathur (umathur@arsdigita.com) + * @author Jens Pelzetter + * */ + +public interface TaskURLGenerator { + + String generateURL(long item_id, long task_id); +} diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/ContentItem.java b/ccm-cms/src/main/java/org/librecms/contentsection/ContentItem.java index 7050f3447..8a1a02513 100644 --- a/ccm-cms/src/main/java/org/librecms/contentsection/ContentItem.java +++ b/ccm-cms/src/main/java/org/librecms/contentsection/ContentItem.java @@ -65,67 +65,77 @@ import static org.librecms.CmsConstants.*; @Table(name = "CONTENT_ITEMS", schema = DB_SCHEMA) @NamedQueries({ @NamedQuery( - name = "ContentItem.findByType", - query = "SELECT i FROM ContentItem i WHERE TYPE(i) = :type") + name = "ContentItem.findByType", + query = "SELECT i FROM ContentItem i WHERE TYPE(i) = :type") , @NamedQuery( - name = "ContentItem.findByFolder", - query = "SELECT i FROM ContentItem i " - + "JOIN i.categories c " - + "WHERE c.category = :folder " - + "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + "'") + name = "ContentItem.findByFolder", + query = "SELECT i FROM ContentItem i " + + "JOIN i.categories c " + + "WHERE c.category = :folder " + + "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + + "'") , @NamedQuery( - name = "ContentItem.countItemsInFolder", - query = "SELECT count(i) FROM ContentItem i " - + "JOIN i.categories c " - + "WHERE c.category = :folder " - + "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + "'") + name = "ContentItem.countItemsInFolder", + query = "SELECT count(i) FROM ContentItem i " + + "JOIN i.categories c " + + "WHERE c.category = :folder " + + "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + + "'") , @NamedQuery( - name = "ContentItem.countByNameInFolder", - query = "SELECT COUNT(i) FROM ContentItem i " - + "JOIN i.categories c " - + "WHERE c.category = :folder " - + "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + "' " - + "AND i.displayName = :name") + name = "ContentItem.countByNameInFolder", + query = "SELECT COUNT(i) FROM ContentItem i " + + "JOIN i.categories c " + + "WHERE c.category = :folder " + + "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + + "' " + + "AND i.displayName = :name") , @NamedQuery( - name = "ContentItem.filterByFolderAndName", - query = "SELECT i FROM ContentItem i " - + "JOIN i.categories c " - + "WHERE c.category = :folder " - + "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + "' " - + "AND LOWER(i.displayName) LIKE CONCAT(LOWER(:name), '%')") + name = "ContentItem.filterByFolderAndName", + query = "SELECT i FROM ContentItem i " + + "JOIN i.categories c " + + "WHERE c.category = :folder " + + "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + + "' " + + "AND LOWER(i.displayName) LIKE CONCAT(LOWER(:name), '%')") , @NamedQuery( - name = "ContentItem.countFilterByFolderAndName", - query = "SELECT COUNT(i) FROM ContentItem i " - + "JOIN i.categories c " - + "WHERE c.category = :folder " - + "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + "' " - + "AND LOWER(i.displayName) LIKE CONCAT(LOWER(:name), '%')" + name = "ContentItem.countFilterByFolderAndName", + query = "SELECT COUNT(i) FROM ContentItem i " + + "JOIN i.categories c " + + "WHERE c.category = :folder " + + "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + + "' " + + "AND LOWER(i.displayName) LIKE CONCAT(LOWER(:name), '%')" ) , @NamedQuery( - name = "ContentItem.hasLiveVersion", - query = "SELECT (CASE WHEN COUNT(i) > 0 THEN true ELSE false END) " - + "FROM ContentItem i " - + "WHERE i.itemUuid = :uuid " - + "AND i.version = org.librecms.contentsection.ContentItemVersion.LIVE") + name = "ContentItem.hasLiveVersion", + query = "SELECT (CASE WHEN COUNT(i) > 0 THEN true ELSE false END) " + + "FROM ContentItem i " + + "WHERE i.itemUuid = :uuid " + + "AND i.version = org.librecms.contentsection.ContentItemVersion.LIVE") , @NamedQuery( - name = "ContentItem.findDraftVersion", - query = "SELECT i FROM ContentItem i " - + "WHERE i.itemUuid = :uuid " - + "AND i.version = org.librecms.contentsection.ContentItemVersion.DRAFT") + name = "ContentItem.findDraftVersion", + query = "SELECT i FROM ContentItem i " + + "WHERE i.itemUuid = :uuid " + + "AND i.version = org.librecms.contentsection.ContentItemVersion.DRAFT") , @NamedQuery( - name = "ContentItem.findLiveVersion", - query = "SELECT i FROM ContentItem i " - + "WHERE i.itemUuid = :uuid " - + "AND i.version = org.librecms.contentsection.ContentItemVersion.LIVE") - + name = "ContentItem.findLiveVersion", + query = "SELECT i FROM ContentItem i " + + "WHERE i.itemUuid = :uuid " + + "AND i.version = org.librecms.contentsection.ContentItemVersion.LIVE") + , + @NamedQuery( + name = "ContentItem.findItemWithWorkflow", + query = "SELECT i FROM ContentItem i " + + "WHERE i.workflow = :workflow" + ) }) public class ContentItem extends CcmObject implements Serializable, InheritsPermissions { @@ -143,13 +153,13 @@ public class ContentItem extends CcmObject implements Serializable, */ @Embedded @AssociationOverride( - name = "values", - joinTable = @JoinTable(name = "CONTENT_ITEM_NAMES", - schema = DB_SCHEMA, - joinColumns = { - @JoinColumn(name = "OBJECT_ID") - } - ) + name = "values", + joinTable = @JoinTable(name = "CONTENT_ITEM_NAMES", + schema = DB_SCHEMA, + joinColumns = { + @JoinColumn(name = "OBJECT_ID") + } + ) ) private LocalizedString name; @@ -166,13 +176,13 @@ public class ContentItem extends CcmObject implements Serializable, */ @Embedded @AssociationOverride( - name = "values", - joinTable = @JoinTable(name = "CONTENT_ITEM_TITLES", - schema = DB_SCHEMA, - joinColumns = { - @JoinColumn(name = "OBJECT_ID") - } - ) + name = "values", + joinTable = @JoinTable(name = "CONTENT_ITEM_TITLES", + schema = DB_SCHEMA, + joinColumns = { + @JoinColumn(name = "OBJECT_ID") + } + ) ) private LocalizedString title; @@ -181,12 +191,12 @@ public class ContentItem extends CcmObject implements Serializable, */ @Embedded @AssociationOverride( - name = "values", - joinTable = @JoinTable(name = "CONTENT_ITEM_DESCRIPTIONS", - schema = DB_SCHEMA, - joinColumns = { - @JoinColumn(name = "OBJECT_ID")} - )) + name = "values", + joinTable = @JoinTable(name = "CONTENT_ITEM_DESCRIPTIONS", + schema = DB_SCHEMA, + joinColumns = { + @JoinColumn(name = "OBJECT_ID")} + )) private LocalizedString description; /** @@ -342,10 +352,10 @@ public class ContentItem extends CcmObject implements Serializable, @Override public Optional getParent() { final List result = getCategories().stream().filter( - categorization -> CmsConstants.CATEGORIZATION_TYPE_FOLDER. - equals( - categorization.getType())) - .collect(Collectors.toList()); + categorization -> CmsConstants.CATEGORIZATION_TYPE_FOLDER. + equals( + categorization.getType())) + .collect(Collectors.toList()); if (result.isEmpty()) { return Optional.empty(); @@ -424,15 +434,15 @@ public class ContentItem extends CcmObject implements Serializable, @Override public String toString(final String data) { return super.toString(String.format(", itemUuid = %s, " - + "name = %s, " - + "contentType = { %s }, " - + "title = %s, " - + "description = %s, " - + "version = %s, " - + "launchDate = %s, " - + "lifecycle = { %s }, " - + "workflow = { %s }" - + "%s", + + "name = %s, " + + "contentType = { %s }, " + + "title = %s, " + + "description = %s, " + + "version = %s, " + + "launchDate = %s, " + + "lifecycle = { %s }, " + + "workflow = { %s }" + + "%s", itemUuid, Objects.toString(name), Objects.toString(contentType), diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemManager.java b/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemManager.java index b0dd3347a..785df460c 100644 --- a/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemManager.java +++ b/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemManager.java @@ -78,7 +78,7 @@ import javax.transaction.Transactional; public class ContentItemManager { private static final Logger LOGGER = LogManager.getLogger( - ContentItemManager.class); + ContentItemManager.class); @Inject private EntityManager entityManager; @@ -121,31 +121,31 @@ public class ContentItemManager { * {@link ContentSection#rootDocumentsFolder} of the provided content * section. Otherwise an {@link IllegalArgumentException} is thrown. * - * @param The type of the content item. - * @param name The name (URL stub) of the new content item. + * @param The type of the content item. + * @param name The name (URL stub) of the new content item. * @param section The content section in which the item is generated. - * @param folder The folder in which in the item is stored. - * @param type The type of the new content item. + * @param folder The folder in which in the item is stored. + * @param type The type of the new content item. * * @return The new content item. */ @AuthorizationRequired @Transactional(Transactional.TxType.REQUIRED) public T createContentItem( - final String name, - final ContentSection section, - @RequiresPrivilege(ItemPrivileges.CREATE_NEW) - final Folder folder, - final Class type) { + final String name, + final ContentSection section, + @RequiresPrivilege(ItemPrivileges.CREATE_NEW) + final Folder folder, + final Class type) { final Optional contentType = typeRepo - .findByContentSectionAndClass(section, type); + .findByContentSectionAndClass(section, type); if (!contentType.isPresent()) { throw new IllegalArgumentException(String.format( - "ContentSection \"%s\" has no content type for \"%s\".", - section.getLabel(), - type.getName())); + "ContentSection \"%s\" has no content type for \"%s\".", + section.getLabel(), + type.getName())); } return createContentItem(name, @@ -167,39 +167,40 @@ public class ContentItemManager { * provided content section. Otherwise an {@link IllegalArgumentException} * is thrown. * - * @param The type of the content item. - * @param name The name (URL stub) of the new content item. - * @param section The content section in which the item is generated. - * @param folder The folder in which in the item is stored. + * @param The type of the content item. + * @param name The name (URL stub) of the new content item. + * @param section The content section in which the item is + * generated. + * @param folder The folder in which in the item is stored. * @param workflowTemplate The template for the workflow to apply to the new - * item. - * @param type The type of the new content item. + * item. + * @param type The type of the new content item. * * @return The new content item. */ @AuthorizationRequired @Transactional(Transactional.TxType.REQUIRED) public T createContentItem( - final String name, - final ContentSection section, - @RequiresPrivilege(ItemPrivileges.CREATE_NEW) - final Folder folder, - final WorkflowTemplate workflowTemplate, - final Class type) { + final String name, + final ContentSection section, + @RequiresPrivilege(ItemPrivileges.CREATE_NEW) + final Folder folder, + final WorkflowTemplate workflowTemplate, + final Class type) { final Optional contentType = typeRepo - .findByContentSectionAndClass(section, type); + .findByContentSectionAndClass(section, type); if (!contentType.isPresent()) { throw new IllegalArgumentException(String.format( - "ContentSection \"%s\" has no content type for \"%s\".", - section.getLabel(), - type.getName())); + "ContentSection \"%s\" has no content type for \"%s\".", + section.getLabel(), + type.getName())); } if (name == null || name.trim().isEmpty()) { throw new IllegalArgumentException( - "The name of a content item can't be blank."); + "The name of a content item can't be blank."); } final T item; @@ -207,14 +208,14 @@ public class ContentItemManager { item = type.newInstance(); } catch (InstantiationException | IllegalAccessException ex) { LOGGER.error("Failed to create new content item of type \"{}\" " - + "in content section \"{}\".", + + "in content section \"{}\".", type.getName(), section.getLabel()); throw new RuntimeException(ex); } final KernelConfig kernelConfig = confManager.findConfiguration( - KernelConfig.class); + KernelConfig.class); item.setDisplayName(name); item.getName().addValue(kernelConfig.getDefaultLocale(), @@ -225,16 +226,16 @@ public class ContentItemManager { if (workflowTemplate != null) { final Workflow workflow = workflowManager.createWorkflow( - workflowTemplate); + workflowTemplate, item); item.setWorkflow(workflow); } contentItemRepo.save(item); categoryManager.addObjectToCategory( - item, - folder, - CATEGORIZATION_TYPE_FOLDER); + item, + folder, + CATEGORIZATION_TYPE_FOLDER); contentItemRepo.save(item); @@ -252,23 +253,23 @@ public class ContentItemManager { * only moves the draft version of the item. The live version is moved after * a the item is republished. * - * @param item The item to move. + * @param item The item to move. * @param targetFolder The folder to which the item is moved. */ @AuthorizationRequired @Transactional(Transactional.TxType.REQUIRED) public void move( - @RequiresPrivilege(ItemPrivileges.EDIT) - final ContentItem item, - @RequiresPrivilege(ItemPrivileges.CREATE_NEW) - final Folder targetFolder) { + @RequiresPrivilege(ItemPrivileges.EDIT) + final ContentItem item, + @RequiresPrivilege(ItemPrivileges.CREATE_NEW) + final Folder targetFolder) { if (item == null) { throw new IllegalArgumentException("The item to move can't be null."); } if (targetFolder == null) { throw new IllegalArgumentException( - "The target folder can't be null."); + "The target folder can't be null."); } final ContentItem draftItem = getDraftVersion(item, item.getClass()); @@ -277,18 +278,18 @@ public class ContentItemManager { if (!sectionManager.hasContentType(draftItem.getClass(), targetFolder.getSection())) { throw new IllegalArgumentException(String.format( - "Can't move item %d:\"%s\" to folder \"%s\"." - + "The target folder %d:\"%s\" belongs to content section " + "Can't move item %d:\"%s\" to folder \"%s\"." + + "The target folder %d:\"%s\" belongs to content section " + "%d:\"%s\". The content type \"%s\" has not registered" - + "for this section.", - draftItem.getObjectId(), - draftItem.getDisplayName(), - folderManager.getFolderPath(targetFolder, true), - targetFolder.getObjectId(), - targetFolder.getDisplayName(), - targetFolder.getSection().getObjectId(), - targetFolder.getSection().getDisplayName(), - draftItem.getClass().getName())); + + "for this section.", + draftItem.getObjectId(), + draftItem.getDisplayName(), + folderManager.getFolderPath(targetFolder, true), + targetFolder.getObjectId(), + targetFolder.getDisplayName(), + targetFolder.getSection().getObjectId(), + targetFolder.getSection().getDisplayName(), + draftItem.getClass().getName())); } if (currentFolder.isPresent()) { @@ -301,9 +302,9 @@ public class ContentItemManager { } categoryManager.addObjectToCategory( - draftItem, - targetFolder, - CATEGORIZATION_TYPE_FOLDER); + draftItem, + targetFolder, + CATEGORIZATION_TYPE_FOLDER); } @@ -317,10 +318,11 @@ public class ContentItemManager { * section and the type of the item is not registered for the target section * an {@link IllegalArgumentException} is thrown. * - * @param item The item to copy. + * @param item The item to copy. * @param targetFolder The folder in which the copy is created. If the - * target folder is the same folder as the folder of the original item an - * index is appended to the name of the item. + * target folder is the same folder as the folder of the + * original item an index is appended to the name of the + * item. * * @return The copy of the item */ @@ -328,9 +330,9 @@ public class ContentItemManager { @AuthorizationRequired @SuppressWarnings("unchecked") public ContentItem copy( - final ContentItem item, - @RequiresPrivilege(ItemPrivileges.CREATE_NEW) - final Folder targetFolder) { + final ContentItem item, + @RequiresPrivilege(ItemPrivileges.CREATE_NEW) + final Folder targetFolder) { if (item == null) { throw new IllegalArgumentException("The item to copy can't be null."); @@ -338,36 +340,36 @@ public class ContentItemManager { if (targetFolder == null) { throw new IllegalArgumentException( - "The target folder to which the item is copied can't be null"); + "The target folder to which the item is copied can't be null"); } final Optional contentType = typeRepo - .findByContentSectionAndClass( - targetFolder.getSection(), item.getClass()); + .findByContentSectionAndClass( + targetFolder.getSection(), item.getClass()); if (!contentType.isPresent()) { throw new IllegalArgumentException(String.format( - "ContentSection \"%s\" has no content type for \"%s\".", - item.getContentType().getContentSection(), - item.getClass().getName())); + "ContentSection \"%s\" has no content type for \"%s\".", + item.getContentType().getContentSection(), + item.getClass().getName())); } final ContentItem draftItem = getDraftVersion(item, item.getClass()); if (!sectionManager.hasContentType(draftItem.getClass(), targetFolder.getSection())) { throw new IllegalArgumentException(String.format( - "Can't copy item %d:\"%s\" to folder \"%s\"." - + "The target folder %d:\"%s\" belongs to content section " + "Can't copy item %d:\"%s\" to folder \"%s\"." + + "The target folder %d:\"%s\" belongs to content section " + "%d:\"%s\". The content type \"%s\" has not registered" - + "for this section.", - draftItem.getObjectId(), - draftItem.getDisplayName(), - folderManager.getFolderPath(targetFolder, true), - targetFolder.getObjectId(), - targetFolder.getDisplayName(), - targetFolder.getSection().getObjectId(), - targetFolder.getSection().getDisplayName(), - draftItem.getClass().getName())); + + "for this section.", + draftItem.getObjectId(), + draftItem.getDisplayName(), + folderManager.getFolderPath(targetFolder, true), + targetFolder.getObjectId(), + targetFolder.getDisplayName(), + targetFolder.getSection().getObjectId(), + targetFolder.getSection().getDisplayName(), + draftItem.getClass().getName())); } final ContentItem copy; @@ -381,31 +383,31 @@ public class ContentItemManager { if (draftItem.getWorkflow() != null) { final WorkflowTemplate template = draftItem.getWorkflow() - .getTemplate(); + .getTemplate(); final Workflow copyWorkflow = workflowManager.createWorkflow( - template); + template, item); copy.setWorkflow(copyWorkflow); } contentItemRepo.save(copy); draftItem.getCategories().forEach(categorization -> categoryManager - .addObjectToCategory(copy, categorization.getCategory())); + .addObjectToCategory(copy, categorization.getCategory())); final Optional itemFolder = getItemFolder(draftItem); if (itemFolder.isPresent()) { try { categoryManager.removeObjectFromCategory( - copy, getItemFolder(draftItem).get()); + copy, getItemFolder(draftItem).get()); } catch (ObjectNotAssignedToCategoryException ex) { throw new RuntimeException(ex); } } categoryManager.addObjectToCategory( - copy, - targetFolder, - CATEGORIZATION_TYPE_FOLDER); + copy, + targetFolder, + CATEGORIZATION_TYPE_FOLDER); for (AttachmentList attachmentList : item.getAttachments()) { copyAttachmentList(attachmentList, copy); @@ -419,7 +421,7 @@ public class ContentItemManager { } for (final PropertyDescriptor propertyDescriptor : beanInfo - .getPropertyDescriptors()) { + .getPropertyDescriptors()) { if (propertyIsExcluded(propertyDescriptor.getName())) { continue; } @@ -439,50 +441,50 @@ public class ContentItemManager { source = (LocalizedString) readMethod.invoke(draftItem); target = (LocalizedString) readMethod.invoke(copy); } catch (IllegalAccessException - | IllegalArgumentException - | InvocationTargetException ex) { + | IllegalArgumentException + | InvocationTargetException ex) { throw new RuntimeException(ex); } copyLocalizedString(source, target); } else if (propType != null - && propType.isAssignableFrom(ContentItem.class)) { + && propType.isAssignableFrom(ContentItem.class)) { final ContentItem linkedItem; try { linkedItem = (ContentItem) readMethod.invoke(draftItem); } catch (IllegalAccessException - | IllegalArgumentException - | InvocationTargetException ex) { + | IllegalArgumentException + | InvocationTargetException ex) { throw new RuntimeException(ex); } final ContentItem linkedDraftItem = getDraftVersion( - linkedItem, linkedItem.getClass()); + linkedItem, linkedItem.getClass()); try { writeMethod.invoke(copy, linkedDraftItem); } catch (IllegalAccessException - | IllegalArgumentException - | InvocationTargetException ex) { + | IllegalArgumentException + | InvocationTargetException ex) { throw new RuntimeException(ex); } } else if (propType != null - && propType.isAssignableFrom(List.class)) { + && propType.isAssignableFrom(List.class)) { final List source; final List target; try { source = (List) readMethod.invoke(draftItem); target = (List) readMethod.invoke(copy); } catch (IllegalAccessException - | IllegalArgumentException - | InvocationTargetException ex) { + | IllegalArgumentException + | InvocationTargetException ex) { throw new RuntimeException(ex); } target.addAll(source); } else if (propType != null - && propType.isAssignableFrom(Map.class)) { + && propType.isAssignableFrom(Map.class)) { final Map source; final Map target; @@ -490,14 +492,14 @@ public class ContentItemManager { source = (Map) readMethod.invoke(draftItem); target = (Map) readMethod.invoke(copy); } catch (IllegalAccessException - | IllegalArgumentException - | InvocationTargetException ex) { + | IllegalArgumentException + | InvocationTargetException ex) { throw new RuntimeException(ex); } source.forEach((key, value) -> target.put(key, value)); } else if (propType != null - && propType.isAssignableFrom(Set.class)) { + && propType.isAssignableFrom(Set.class)) { final Set source; final Set target; @@ -505,8 +507,8 @@ public class ContentItemManager { source = (Set) readMethod.invoke(draftItem); target = (Set) readMethod.invoke(copy); } catch (IllegalAccessException - | IllegalArgumentException - | InvocationTargetException ex) { + | IllegalArgumentException + | InvocationTargetException ex) { throw new RuntimeException(ex); } @@ -517,8 +519,8 @@ public class ContentItemManager { value = readMethod.invoke(draftItem); writeMethod.invoke(copy, value); } catch (IllegalAccessException - | IllegalArgumentException - | InvocationTargetException ex) { + | IllegalArgumentException + | InvocationTargetException ex) { throw new RuntimeException(ex); } } @@ -526,8 +528,8 @@ public class ContentItemManager { if (targetFolder.equals(getItemFolder(item).orElse(null))) { final long number = contentItemRepo.countFilterByFolderAndName( - targetFolder, String.format("%s_copy", - item.getDisplayName())); + targetFolder, String.format("%s_copy", + item.getDisplayName())); final long index = number + 1; copy.setDisplayName(String.format("%s_copy%d", copy.getDisplayName(), @@ -562,7 +564,8 @@ public class ContentItemManager { private void copyAttachmentList(final AttachmentList sourceList, final ContentItem target) { final AttachmentList targetList = new AttachmentList(); - copyLocalizedString(sourceList.getDescription(), targetList.getDescription()); + copyLocalizedString(sourceList.getDescription(), targetList + .getDescription()); targetList.setItem(target); targetList.setName(sourceList.getName()); targetList.setOrder(sourceList.getOrder()); @@ -630,12 +633,12 @@ public class ContentItemManager { if (!source.getClass().equals(target.getClass())) { throw new IllegalArgumentException(String.format( - "Asset belong to different classes. source is instance of " - + "\"%s\", target is instance of \"%s\". It is not " - + "possible to use assets of diffierent classes " - + "with this method", - source.getClass().getName(), - target.getClass().getName())); + "Asset belong to different classes. source is instance of " + + "\"%s\", target is instance of \"%s\". It is not " + + "possible to use assets of diffierent classes " + + "with this method", + source.getClass().getName(), + target.getClass().getName())); } final BeanInfo beanInfo; @@ -646,12 +649,12 @@ public class ContentItemManager { } for (final PropertyDescriptor propertyDescriptor : beanInfo. - getPropertyDescriptors()) { + getPropertyDescriptors()) { final String propertyName = propertyDescriptor.getName(); if ("objectId".equals(propertyName) - || "uuid".equals(propertyName) - || "itemAttachments".equals(propertyName) - || "categories".equals(propertyName)) { + || "uuid".equals(propertyName) + || "itemAttachments".equals(propertyName) + || "categories".equals(propertyName)) { continue; } @@ -670,8 +673,8 @@ public class ContentItemManager { sourceStr = (LocalizedString) readMethod.invoke(source); targetStr = (LocalizedString) readMethod.invoke(target); } catch (IllegalAccessException - | IllegalArgumentException - | InvocationTargetException ex) { + | IllegalArgumentException + | InvocationTargetException ex) { throw new UncheckedWrapperException(ex); } @@ -682,8 +685,8 @@ public class ContentItemManager { value = readMethod.invoke(source); writeMethod.invoke(target, value); } catch (IllegalAccessException - | IllegalArgumentException - | InvocationTargetException ex) { + | IllegalArgumentException + | InvocationTargetException ex) { throw new UncheckedWrapperException(ex); } } @@ -713,16 +716,16 @@ public class ContentItemManager { @AuthorizationRequired @Transactional(Transactional.TxType.REQUIRED) public ContentItem publish( - @RequiresPrivilege(ItemPrivileges.PUBLISH) - final ContentItem item) { + @RequiresPrivilege(ItemPrivileges.PUBLISH) + final ContentItem item) { if (item == null) { throw new IllegalArgumentException( - "The item to publish can't be null."); + "The item to publish can't be null."); } final LifecycleDefinition lifecycleDefinition = item.getContentType() - .getDefaultLifecycle(); + .getDefaultLifecycle(); return publish(item, lifecycleDefinition); } @@ -731,9 +734,9 @@ public class ContentItemManager { * Creates a live version of content item or updates the live version of a * content item if there already a live version. * - * @param item The content item to publish. + * @param item The content item to publish. * @param lifecycleDefinition The definition of the lifecycle to use for the - * new item. + * new item. * * @return The published content item. */ @@ -741,19 +744,19 @@ public class ContentItemManager { @Transactional(Transactional.TxType.REQUIRED) @SuppressWarnings("unchecked") public ContentItem publish( - @RequiresPrivilege(ItemPrivileges.PUBLISH) - final ContentItem item, - final LifecycleDefinition lifecycleDefinition) { + @RequiresPrivilege(ItemPrivileges.PUBLISH) + final ContentItem item, + final LifecycleDefinition lifecycleDefinition) { if (item == null) { throw new IllegalArgumentException( - "The item to publish can't be null."); + "The item to publish can't be null."); } if (lifecycleDefinition == null) { throw new IllegalArgumentException( - "The lifecycle definition for the " - + "lifecycle of the item to publish can't be null."); + "The lifecycle definition for the " + + "lifecycle of the item to publish can't be null."); } final ContentItem draftItem = getDraftVersion(item, ContentItem.class); @@ -775,16 +778,16 @@ public class ContentItemManager { liveItem.setContentType(draftItem.getContentType()); final Lifecycle lifecycle = lifecycleManager.createLifecycle( - lifecycleDefinition); + lifecycleDefinition); liveItem.setLifecycle(lifecycle); liveItem.setWorkflow(draftItem.getWorkflow()); final List oldCategories = liveItem - .getCategories() - .stream() - .map(categorization -> categorization.getCategory()) - .collect(Collectors.toList()); + .getCategories() + .stream() + .map(categorization -> categorization.getCategory()) + .collect(Collectors.toList()); oldCategories.forEach(category -> { try { categoryManager.removeObjectFromCategory(liveItem, category); @@ -794,9 +797,9 @@ public class ContentItemManager { }); draftItem.getCategories().forEach(categorization -> categoryManager - .addObjectToCategory(liveItem, - categorization.getCategory(), - categorization.getType())); + .addObjectToCategory(liveItem, + categorization.getCategory(), + categorization.getType())); for (int i = 0; i < draftItem.getAttachments().size(); i++) { final AttachmentList sourceList = draftItem.getAttachments().get(i); @@ -804,13 +807,13 @@ public class ContentItemManager { final AttachmentList targetList; if (liveItem.getAttachments().size() < i + 1) { targetList = new AttachmentList(); - copyLocalizedString(sourceList.getDescription(), + copyLocalizedString(sourceList.getDescription(), targetList.getDescription()); - + targetList.setItem(liveItem); liveItem.addAttachmentList(targetList); targetList.setName(sourceList.getName()); - copyLocalizedString(sourceList.getTitle(), + copyLocalizedString(sourceList.getTitle(), targetList.getTitle()); targetList.setOrder(sourceList.getOrder()); targetList.setUuid(UUID.randomUUID().toString()); @@ -820,19 +823,19 @@ public class ContentItemManager { for (int j = 0; j < sourceList.getAttachments().size(); j++) { final ItemAttachment sourceAttachment = sourceList. - getAttachments().get(j); + getAttachments().get(j); final ItemAttachment targetAttachment; if (targetList.getAttachments().size() < j + 1) { targetAttachment = new ItemAttachment<>(); } else { targetAttachment = (ItemAttachment) targetList. - getAttachments().get(j); + getAttachments().get(j); } if (!sourceAttachment.getAsset().equals(targetAttachment)) { final Asset oldTargetAsset = targetAttachment.getAsset(); if (oldTargetAsset != null - && !assetManager.isShared(oldTargetAsset)) { + && !assetManager.isShared(oldTargetAsset)) { targetAttachment.setAsset(null); oldTargetAsset.removeItemAttachment(targetAttachment); entityManager.remove(oldTargetAsset); @@ -844,8 +847,8 @@ public class ContentItemManager { targetAsset = sourceAttachment.getAsset(); } else { try { - targetAsset = sourceAttachment.getAsset().getClass(). - newInstance(); + targetAsset = sourceAttachment.getAsset().getClass() + .newInstance(); } catch (InstantiationException | IllegalAccessException ex) { throw new UncheckedWrapperException(ex); } @@ -878,7 +881,7 @@ public class ContentItemManager { } for (final PropertyDescriptor propertyDescriptor : beanInfo - .getPropertyDescriptors()) { + .getPropertyDescriptors()) { if (propertyIsExcluded(propertyDescriptor.getName())) { continue; @@ -899,54 +902,54 @@ public class ContentItemManager { source = (LocalizedString) readMethod.invoke(draftItem); target = (LocalizedString) readMethod.invoke(liveItem); } catch (IllegalAccessException - | IllegalArgumentException - | InvocationTargetException ex) { + | IllegalArgumentException + | InvocationTargetException ex) { throw new RuntimeException(ex); } copyLocalizedString(source, target); } else if (propType != null - && propType.isAssignableFrom(ContentItem.class)) { + && propType.isAssignableFrom(ContentItem.class)) { final ContentItem linkedItem; try { linkedItem = (ContentItem) readMethod.invoke(draftItem); } catch (IllegalAccessException - | IllegalArgumentException - | InvocationTargetException ex) { + | IllegalArgumentException + | InvocationTargetException ex) { throw new RuntimeException(ex); } final ContentItem linkedDraftItem = getDraftVersion( - linkedItem, linkedItem.getClass()); + linkedItem, linkedItem.getClass()); if (isLive(linkedDraftItem)) { try { final Optional linkedLiveItem - = getLiveVersion( - linkedDraftItem, ContentItem.class); + = getLiveVersion( + linkedDraftItem, ContentItem.class); writeMethod.invoke(liveItem, linkedLiveItem); } catch (IllegalAccessException - | IllegalArgumentException - | InvocationTargetException ex) { + | IllegalArgumentException + | InvocationTargetException ex) { throw new RuntimeException(ex); } } } else if (propType != null - && propType.isAssignableFrom(List.class)) { + && propType.isAssignableFrom(List.class)) { final List source; final List target; try { source = (List) readMethod.invoke(draftItem); target = (List) readMethod.invoke(liveItem); } catch (IllegalAccessException - | IllegalArgumentException - | InvocationTargetException ex) { + | IllegalArgumentException + | InvocationTargetException ex) { throw new RuntimeException(ex); } target.addAll(source); } else if (propType != null - && propType.isAssignableFrom(Map.class)) { + && propType.isAssignableFrom(Map.class)) { final Map source; final Map target; @@ -954,14 +957,14 @@ public class ContentItemManager { source = (Map) readMethod.invoke(draftItem); target = (Map) readMethod.invoke(liveItem); } catch (IllegalAccessException - | IllegalArgumentException - | InvocationTargetException ex) { + | IllegalArgumentException + | InvocationTargetException ex) { throw new RuntimeException(ex); } source.forEach((key, value) -> target.put(key, value)); } else if (propType != null - && propType.isAssignableFrom(Set.class)) { + && propType.isAssignableFrom(Set.class)) { final Set source; final Set target; @@ -969,8 +972,8 @@ public class ContentItemManager { source = (Set) readMethod.invoke(draftItem); target = (Set) readMethod.invoke(liveItem); } catch (IllegalAccessException - | IllegalArgumentException - | InvocationTargetException ex) { + | IllegalArgumentException + | InvocationTargetException ex) { throw new RuntimeException(ex); } @@ -981,8 +984,8 @@ public class ContentItemManager { value = readMethod.invoke(item); writeMethod.invoke(liveItem, value); } catch (IllegalAccessException - | IllegalArgumentException - | InvocationTargetException ex) { + | IllegalArgumentException + | InvocationTargetException ex) { throw new RuntimeException(ex); } } @@ -1004,8 +1007,8 @@ public class ContentItemManager { @AuthorizationRequired @Transactional(Transactional.TxType.REQUIRED) public void publish( - @RequiresPrivilege(ItemPrivileges.PUBLISH) - final Folder folder) { + @RequiresPrivilege(ItemPrivileges.PUBLISH) + final Folder folder) { // Ensure that we are using a fresh folder and that the folder was // retrieved in this transaction to avoid problems with lazy fetched @@ -1013,10 +1016,10 @@ public class ContentItemManager { final Folder theFolder = folderRepo.findById(folder.getObjectId()); theFolder.getObjects() - .stream() - .map(categorization -> categorization.getCategorizedObject()) - .filter(object -> object instanceof ContentItem) - .forEach(item -> publish((ContentItem) item)); + .stream() + .map(categorization -> categorization.getCategorizedObject()) + .filter(object -> object instanceof ContentItem) + .forEach(item -> publish((ContentItem) item)); } /** @@ -1028,17 +1031,17 @@ public class ContentItemManager { @AuthorizationRequired @Transactional(Transactional.TxType.REQUIRED) public void unpublish( - @RequiresPrivilege(ItemPrivileges.PUBLISH) - final ContentItem item) { + @RequiresPrivilege(ItemPrivileges.PUBLISH) + final ContentItem item) { if (item == null) { throw new IllegalArgumentException( - "The item to unpublish can't be null"); + "The item to unpublish can't be null"); } LOGGER.debug("Unpublishing item {}...", item.getItemUuid()); final Optional liveItem = getLiveVersion( - item, ContentItem.class); + item, ContentItem.class); if (!liveItem.isPresent()) { LOGGER.info("ContentItem {} has no live version.", @@ -1047,20 +1050,20 @@ public class ContentItemManager { } final List attachmentLists = liveItem.get() - .getAttachments(); + .getAttachments(); for (final AttachmentList attachmentList : attachmentLists) { attachmentList.getAttachments().forEach( - attachment -> { - unpublishAttachment(attachment); - }); + attachment -> { + unpublishAttachment(attachment); + }); } final List categories = liveItem - .get() - .getCategories() - .stream() - .map(categorization -> categorization.getCategory()) - .collect(Collectors.toList()); + .get() + .getCategories() + .stream() + .map(categorization -> categorization.getCategory()) + .collect(Collectors.toList()); categories.forEach(category -> { try { @@ -1101,8 +1104,8 @@ public class ContentItemManager { @AuthorizationRequired @Transactional(Transactional.TxType.REQUIRED) public void unpublish( - @RequiresPrivilege(ItemPrivileges.PUBLISH) - final Folder folder) { + @RequiresPrivilege(ItemPrivileges.PUBLISH) + final Folder folder) { // Ensure that we are using a fresh folder and that the folder was // retrieved in this transaction to avoid problems with lazy fetched @@ -1110,12 +1113,12 @@ public class ContentItemManager { final Folder theFolder = folderRepo.findById(folder.getObjectId()); theFolder.getObjects() - .stream() - .map(categorization -> categorization.getCategorizedObject()) - .filter(object -> object instanceof ContentItem) - .map(object -> (ContentItem) object) - .filter(item -> isLive(item)) - .forEach(item -> unpublish(item)); + .stream() + .map(categorization -> categorization.getCategorizedObject()) + .filter(object -> object instanceof ContentItem) + .map(object -> (ContentItem) object) + .filter(item -> isLive(item)) + .forEach(item -> unpublish(item)); } /** @@ -1124,12 +1127,12 @@ public class ContentItemManager { * @param item The item * * @return {@code true} if the content item has a live version, - * {@code false} if not. + * {@code false} if not. */ @Transactional(Transactional.TxType.REQUIRED) public boolean isLive(final ContentItem item) { final TypedQuery query = entityManager.createNamedQuery( - "ContentItem.hasLiveVersion", Boolean.class); + "ContentItem.hasLiveVersion", Boolean.class); query.setParameter("uuid", item.getItemUuid()); return query.getSingleResult(); @@ -1138,35 +1141,35 @@ public class ContentItemManager { /** * Retrieves the live version of the provided content item if any. * - * @param Type of the content item. + * @param Type of the content item. * @param item The item of which the live version should be retrieved. * @param type Type of the content item. * * @return The live version of an item. If the item provided is already the - * live version the provided item is returned, otherwise the live version is - * returned. If there is no live version an empty {@link Optional} is - * returned. + * live version the provided item is returned, otherwise the live + * version is returned. If there is no live version an empty + * {@link Optional} is returned. */ @AuthorizationRequired @Transactional(Transactional.TxType.REQUIRED) @SuppressWarnings({"unchecked"}) public Optional getLiveVersion( - @RequiresPrivilege(ItemPrivileges.VIEW_PUBLISHED) - final ContentItem item, - final Class type) { + @RequiresPrivilege(ItemPrivileges.VIEW_PUBLISHED) + final ContentItem item, + final Class type) { if (!ContentItem.class.isAssignableFrom(type)) { throw new IllegalArgumentException(String.format( - "The provided type \"%s\" does match the type of the provided " + "The provided type \"%s\" does match the type of the provided " + "item (\"%s\").", - type.getName(), - item.getClass().getName())); + type.getName(), + item.getClass().getName())); } if (isLive(item)) { final TypedQuery query = entityManager - .createNamedQuery( - "ContentItem.findLiveVersion", ContentItem.class); + .createNamedQuery( + "ContentItem.findLiveVersion", ContentItem.class); query.setParameter("uuid", item.getItemUuid()); final ContentItem result = query.getSingleResult(); @@ -1183,50 +1186,50 @@ public class ContentItemManager { /** * Retrieves the pending versions of an item if there are any. * - * @param Type of the content item to retrieve. + * @param Type of the content item to retrieve. * @param item The item of which the pending versions are retrieved. * @param type Type of the content item to retrieve. * * @return A list of the pending versions of the item. */ public List getPendingVersions( - final ContentItem item, - final Class type) { + final ContentItem item, + final Class type) { throw new UnsupportedOperationException(); } /** * Retrieves the draft version * - * @param Type of the item. + * @param Type of the item. * @param item The item of which the draft version is retrieved. * @param type Type of the item. * * @return The draft version of the provided content item. If the provided - * item is the draft version the provided item is simply returned. Otherwise - * the draft version is retrieved from the database and is returned. Each - * content item has a draft version (otherwise something is seriously wrong - * with the database) this method will + * item is the draft version the provided item is simply returned. + * Otherwise the draft version is retrieved from the database and is + * returned. Each content item has a draft version (otherwise + * something is seriously wrong with the database) this method will * never return {@code null}. */ @AuthorizationRequired @Transactional(Transactional.TxType.REQUIRED) @SuppressWarnings("unchecked") public T getDraftVersion( - @RequiresPrivilege(ItemPrivileges.PREVIEW) - final ContentItem item, - final Class type) { + @RequiresPrivilege(ItemPrivileges.PREVIEW) + final ContentItem item, + final Class type) { if (!ContentItem.class.isAssignableFrom(type)) { throw new IllegalArgumentException(String.format( - "The provided type \"%s\" does match the type of the provided " + "The provided type \"%s\" does match the type of the provided " + "item (\"%s\").", - type.getName(), - item.getClass().getName())); + type.getName(), + item.getClass().getName())); } final TypedQuery query = entityManager.createNamedQuery( - "ContentItem.findDraftVersion", ContentItem.class); + "ContentItem.findDraftVersion", ContentItem.class); query.setParameter("uuid", item.getItemUuid()); return (T) query.getSingleResult(); @@ -1265,9 +1268,9 @@ public class ContentItemManager { * {@code info}, the path including the content section would be * {@code info:/research/computer-science/artificial-intelligence/neural-nets}. * - * @param item The item whose path is generated. + * @param item The item whose path is generated. * @param withContentSection Whether to include the content section into the - * path. + * path. * * @return The path of the content item * @@ -1276,11 +1279,11 @@ public class ContentItemManager { public String getItemPath(final ContentItem item, final boolean withContentSection) { final List result = item.getCategories().stream() - .filter(categorization -> { - return CATEGORIZATION_TYPE_FOLDER.equals( - categorization.getType()); - }) - .collect(Collectors.toList()); + .filter(categorization -> { + return CATEGORIZATION_TYPE_FOLDER.equals( + categorization.getType()); + }) + .collect(Collectors.toList()); if (result.isEmpty()) { return item.getDisplayName(); @@ -1299,9 +1302,9 @@ public class ContentItemManager { if (withContentSection) { final String sectionName = item.getContentType(). - getContentSection().getDisplayName(); + getContentSection().getDisplayName(); return String.format( - "%s:/%s", sectionName, path); + "%s:/%s", sectionName, path); } else { return String.format("/%s", path); } @@ -1317,11 +1320,11 @@ public class ContentItemManager { */ public List getItemFolders(final ContentItem item) { final List result = item.getCategories().stream() - .filter(categorization -> { - return CATEGORIZATION_TYPE_FOLDER.equals( - categorization.getType()); - }) - .collect(Collectors.toList()); + .filter(categorization -> { + return CATEGORIZATION_TYPE_FOLDER.equals( + categorization.getType()); + }) + .collect(Collectors.toList()); final List folders = new ArrayList<>(); if (!result.isEmpty()) { @@ -1330,12 +1333,12 @@ public class ContentItemManager { folders.add((Folder) current); } else { throw new IllegalArgumentException(String.format( - "The item %s is assigned to the category %s with the" - + "categorization type \"%s\", but the Category is not" + "The item %s is assigned to the category %s with the" + + "categorization type \"%s\", but the Category is not" + "a folder. This is no supported.", - item.getUuid(), - current.getUuid(), - CATEGORIZATION_TYPE_FOLDER)); + item.getUuid(), + current.getUuid(), + CATEGORIZATION_TYPE_FOLDER)); } while (current.getParentCategory() != null) { @@ -1344,12 +1347,12 @@ public class ContentItemManager { folders.add((Folder) current); } else { throw new IllegalArgumentException(String.format( - "The item %s is assigned to the category %s with the" + "The item %s is assigned to the category %s with the" + "categorization type \"%s\", but the Category is not" - + "a folder. This is no supported.", - item.getUuid(), - current.getUuid(), - CATEGORIZATION_TYPE_FOLDER)); + + "a folder. This is no supported.", + item.getUuid(), + current.getUuid(), + CATEGORIZATION_TYPE_FOLDER)); } } @@ -1367,15 +1370,15 @@ public class ContentItemManager { * @param item The item * * @return An {@link Optional} containing the folder of the item if the item - * is part of a folder. + * is part of a folder. */ public Optional getItemFolder(final ContentItem item) { final List result = item.getCategories().stream() - .filter(categorization -> { - return CATEGORIZATION_TYPE_FOLDER. - equals(categorization.getType()); - }) - .collect(Collectors.toList()); + .filter(categorization -> { + return CATEGORIZATION_TYPE_FOLDER. + equals(categorization.getType()); + }) + .collect(Collectors.toList()); if (result.size() > 0) { final Category category = result.get(0).getCategory(); @@ -1383,12 +1386,12 @@ public class ContentItemManager { return Optional.of((Folder) category); } else { throw new IllegalArgumentException(String.format( - "The item %s is assigned to the category %s with the" - + "categorization type \"%s\", but the Category is not" + "The item %s is assigned to the category %s with the" + + "categorization type \"%s\", but the Category is not" + "a folder. This is no supported.", - item.getUuid(), - category.getUuid(), - CATEGORIZATION_TYPE_FOLDER)); + item.getUuid(), + category.getUuid(), + CATEGORIZATION_TYPE_FOLDER)); } } else { return Optional.empty(); diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemRepository.java b/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemRepository.java index fe4acd8e6..3961a25da 100644 --- a/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemRepository.java +++ b/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemRepository.java @@ -29,7 +29,9 @@ import java.util.UUID; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; +import javax.persistence.NoResultException; import javax.persistence.TypedQuery; +import org.libreccm.workflow.Workflow; /** * Repository for content items. @@ -251,4 +253,17 @@ public class ContentItemRepository return query.getSingleResult(); } + public Optional findItemWithWorkflow(final Workflow workflow) { + final TypedQuery query = getEntityManager() + .createNamedQuery("ContentItem.findItemWithWorkflow", + ContentItem.class); + query.setParameter("workflow", workflow); + + try { + return Optional.of(query.getSingleResult()); + } catch(NoResultException ex) { + return Optional.empty(); + } + } + } diff --git a/ccm-cms/src/main/java/org/librecms/workflow/CmsTask.java b/ccm-cms/src/main/java/org/librecms/workflow/CmsTask.java index 893465a33..fa22ec0cf 100644 --- a/ccm-cms/src/main/java/org/librecms/workflow/CmsTask.java +++ b/ccm-cms/src/main/java/org/librecms/workflow/CmsTask.java @@ -18,14 +18,15 @@ */ package org.librecms.workflow; -import org.libreccm.workflow.UserTask; +import org.libreccm.workflow.AssignableTask; import java.io.Serializable; import java.util.Objects; +import javax.persistence.Column; import javax.persistence.Entity; -import javax.persistence.JoinColumn; -import javax.persistence.OneToOne; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; import javax.persistence.Table; import static org.librecms.CmsConstants.*; @@ -36,12 +37,12 @@ import static org.librecms.CmsConstants.*; */ @Entity @Table(name = "WORKFLOW_TASKS", schema = DB_SCHEMA) -public class CmsTask extends UserTask implements Serializable { +public class CmsTask extends AssignableTask implements Serializable { private static final long serialVersionUID = -3988352366529930659L; - @OneToOne - @JoinColumn(name = "TASK_TYPE_ID") + @Column(name = "TASK_TYPE") + @Enumerated(EnumType.STRING) private CmsTaskType taskType; public CmsTaskType getTaskType() { @@ -79,7 +80,7 @@ public class CmsTask extends UserTask implements Serializable { return false; } - return Objects.equals(taskType, other.taskType); + return Objects.equals(taskType, other.getTaskType()); } @Override diff --git a/ccm-cms/src/main/java/org/librecms/workflow/CmsTaskType.java b/ccm-cms/src/main/java/org/librecms/workflow/CmsTaskType.java index a26298a40..9f986db6f 100644 --- a/ccm-cms/src/main/java/org/librecms/workflow/CmsTaskType.java +++ b/ccm-cms/src/main/java/org/librecms/workflow/CmsTaskType.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 LibreCCM Foundation. + * Copyright (C) 2016 LibreCCM Foundation. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,188 +18,38 @@ */ package org.librecms.workflow; -import org.libreccm.l10n.LocalizedString; +import com.arsdigita.cms.workflow.AuthoringTaskURLGenerator; +import com.arsdigita.cms.workflow.DeployTaskURLGenerator; +import com.arsdigita.cms.workflow.EditingTaskURLGenerator; +import com.arsdigita.cms.workflow.TaskURLGenerator; -import java.io.Serializable; -import java.util.Collections; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - -import javax.persistence.AssociationOverride; -import javax.persistence.Column; -import javax.persistence.Embedded; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.OneToMany; -import javax.persistence.Table; - -import static org.librecms.CmsConstants.*; +import org.librecms.contentsection.privileges.ItemPrivileges; /** * * @author Jens Pelzetter */ -@Entity -@Table(name = "WORKFLOW_TASK_TYPES", schema = DB_SCHEMA) -public class CmsTaskType implements Serializable { +public enum CmsTaskType { - private static final long serialVersionUID = -4326031746212785970L; + AUTHOR(AuthoringTaskURLGenerator.class, ItemPrivileges.EDIT), + EDIT(EditingTaskURLGenerator.class, ItemPrivileges.APPROVE), + DEPLOY(DeployTaskURLGenerator.class, ItemPrivileges.PUBLISH); - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - @Column(name = "TASK_TYPE_ID") - private long taskTypeId; + private final Class urlGenerator; + private final String privilege; - @Embedded - @AssociationOverride( - name = "values", - joinTable = @JoinTable(name = "ARTICLE_LEADS", - schema = DB_SCHEMA, - joinColumns = { - @JoinColumn(name = "OBJECT_ID")} - )) - private LocalizedString name; - - @Column(name = "DEFAULT_URL_GENERATOR_CLASS", length = 1024) - private String defaultUrlGeneratorClass; - - @Column(name = "PRIVILEGE", length = 256) - private String privilege; - - @OneToMany - @JoinColumn(name = "TASK_TYPE_ID") - private Set generators; - - public CmsTaskType() { - generators = new HashSet<>(); - } - - public long getTaskTypeId() { - return taskTypeId; - } - - protected void setTaskTypeId(final long taskTypeId) { - this.taskTypeId = taskTypeId; - } - - public LocalizedString getName() { - return name; - } - - public void setName(final LocalizedString name) { - this.name = name; - } - - public String getDefaultUrlGeneratorClass() { - return defaultUrlGeneratorClass; - } - - public void setDefaultUrlGeneratorClass( - final String defaultUrlGeneratorClass) { - this.defaultUrlGeneratorClass = defaultUrlGeneratorClass; - } - - public String getPrivilege() { - return privilege; - } - - public void setPrivilege(final String privilege) { + private CmsTaskType(final Class urlGenerator, + final String privilege) { + this.urlGenerator = urlGenerator; this.privilege = privilege; } - public Set getGenerators() { - if (generators == null) { - return null; - } else { - return Collections.unmodifiableSet(generators); - } + public Class getUrlGenerator() { + return urlGenerator; } - - protected void setGenerators(final Set generators) { - this.generators = generators; + + public String getPrivilege() { + return privilege; } - - public void addGenerator(final TaskEventUrlGenerator generator) { - generators.add(generator); - } - - public void removeGenerator(final TaskEventUrlGenerator generator) { - generators.remove(generator); - } - - @Override - public int hashCode() { - int hash = 5; - hash = 79 * hash + (int) (taskTypeId ^ (taskTypeId >>> 32)); - hash = 79 * hash + Objects.hashCode(name); - hash = 79 * hash + Objects.hashCode(defaultUrlGeneratorClass); - hash = 79 * hash + Objects.hashCode(privilege); - hash = 79 * hash + Objects.hashCode(generators); - return hash; - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (obj instanceof CmsTaskType) { - return false; - } - final CmsTaskType other = (CmsTaskType) obj; - if (!other.canEqual(this)) { - return false; - } - - if (taskTypeId != other.getTaskTypeId()) { - return false; - } - if (!Objects.equals(defaultUrlGeneratorClass, - other.getDefaultUrlGeneratorClass())) { - return false; - } - if (!Objects.equals(privilege, other.getPrivilege())) { - return false; - } - if (!Objects.equals(name, other.getName())) { - return false; - } - - return Objects.equals(generators, other.getGenerators()); - } - - public boolean canEqual(final Object obj) { - return obj instanceof CmsTaskType; - } - - @Override - public final String toString() { - return toString(""); - } - - public String toString(final String data) { - return String.format("%s{ " - + "taskTypeId = %d, " - + "name = %s, " - + "defaultUrlGeneratorClass = \"%s\", " - + "privilege = \"%s\"," - + "generators = { %s }%s" - + " }", - super.toString(), - taskTypeId, - Objects.toString(name), - defaultUrlGeneratorClass, - privilege, - Objects.toString(generators), - data); - } - + } diff --git a/ccm-cms/src/main/java/org/librecms/workflow/CmsTaskTypeRepository.java b/ccm-cms/src/main/java/org/librecms/workflow/CmsTaskTypeRepository.java deleted file mode 100644 index fb50cf97a..000000000 --- a/ccm-cms/src/main/java/org/librecms/workflow/CmsTaskTypeRepository.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2016 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 org.librecms.workflow; - -import org.libreccm.core.AbstractEntityRepository; - -import javax.enterprise.context.RequestScoped; - -/** - * A repository for the {@link CmsTaskType} entity. - * - * @author Jens Pelzetter - */ -@RequestScoped -public class CmsTaskTypeRepository extends AbstractEntityRepository{ - - @Override - public Class getEntityClass() { - return CmsTaskType.class; - } - - @Override - public boolean isNew(final CmsTaskType taskType) { - return taskType.getTaskTypeId() == 0; - } - -} diff --git a/ccm-cms/src/main/java/org/librecms/workflow/TaskEventUrlGenerator.java b/ccm-cms/src/main/java/org/librecms/workflow/TaskEventUrlGenerator.java deleted file mode 100644 index 1b99dc506..000000000 --- a/ccm-cms/src/main/java/org/librecms/workflow/TaskEventUrlGenerator.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2016 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 org.librecms.workflow; - -import org.librecms.contentsection.ContentType; - -import java.io.Serializable; -import java.util.Objects; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.OneToOne; -import javax.persistence.Table; - -import static org.librecms.CmsConstants.*; - -/** - * - * @author Jens Pelzetter - */ -@Entity -@Table(name = "TASK_EVENT_URL_GENERATOR", schema = DB_SCHEMA) -public class TaskEventUrlGenerator implements Serializable { - - private static final long serialVersionUID = -1861545657474968084L; - - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - @Column(name = "GENERATOR_ID") - private long generatorId; - - @Column(name = "EVENT", length = 256) - private String event; - - @OneToOne - @JoinColumn(name = "CONTENT_TYPE_ID") - private ContentType contentType; - - @Column(name = "URL_GENERATOR_CLASS", length = 1024) - private String urlGeneratorClass; - - public long getGeneratorId() { - return generatorId; - } - - public void setGeneratorId(final long generatorId) { - this.generatorId = generatorId; - } - - public String getEvent() { - return event; - } - - public void setEvent(final String event) { - this.event = event; - } - - public ContentType getContentType() { - return contentType; - } - - public void setContentType(final ContentType contentType) { - this.contentType = contentType; - } - - public String getUrlGeneratorClass() { - return urlGeneratorClass; - } - - public void setUrlGeneratorClass(final String urlGeneratorClass) { - this.urlGeneratorClass = urlGeneratorClass; - } - - @Override - public int hashCode() { - int hash = 3; - hash = 47 * hash + (int) (generatorId ^ (generatorId >>> 32)); - hash = 47 * hash + Objects.hashCode(event); - hash = 47 * hash + Objects.hashCode(contentType); - hash = 47 * hash + Objects.hashCode(urlGeneratorClass); - return hash; - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (obj instanceof TaskEventUrlGenerator) { - return false; - } - final TaskEventUrlGenerator other = (TaskEventUrlGenerator) obj; - if (!(other.canEqual(this))) { - return false; - } - - if (generatorId != other.getGeneratorId()) { - return false; - } - if (!Objects.equals(event, other.getEvent())) { - return false; - } - if (!Objects.equals(urlGeneratorClass, other.getUrlGeneratorClass())) { - return false; - } - return Objects.equals(contentType, other.getContentType()); - } - - public boolean canEqual(final Object obj) { - return obj instanceof TaskEventUrlGenerator; - } - - @Override - public final String toString() { - return toString(""); - } - - public String toString(final String data) { - return String.format("%s{ " - + "generatorId = %d, " - + "event = \"%s\", " - + "contentType = %s, " - + "urlGeneratorClass = \"%s\"%s" - + " }", - super.toString(), - generatorId, - event, - Objects.toString(contentType), - urlGeneratorClass, - data); - } - -} diff --git a/ccm-core/src/main/java/org/libreccm/workflow/UserTask.java b/ccm-core/src/main/java/org/libreccm/workflow/AssignableTask.java similarity index 89% rename from ccm-core/src/main/java/org/libreccm/workflow/UserTask.java rename to ccm-core/src/main/java/org/libreccm/workflow/AssignableTask.java index 00a31de2c..dcdd18af2 100644 --- a/ccm-core/src/main/java/org/libreccm/workflow/UserTask.java +++ b/ccm-core/src/main/java/org/libreccm/workflow/AssignableTask.java @@ -45,31 +45,37 @@ import javax.persistence.TemporalType; * @author Jens Pelzetter */ @Entity -@Table(name = "WORKFLOW_USER_TASKS", schema = DB_SCHEMA) +@Table(name = "WORKFLOW_ASSIGNABLE_TASKS", schema = DB_SCHEMA) @NamedQueries({ @NamedQuery( - name = "UserTask.findLockedBy", - query = "SELECT t FROM UserTask t WHERE t.lockingUser = :user") + name = "AssignableTask.findLockedBy", + query = "SELECT t FROM AssignableTask t WHERE t.lockingUser = :user") , @NamedQuery( - name = "UserTask.findEnabledTasksForWorkflow", - query = "SELECT t FROM UserTask t " + name = "AssignableTask.findEnabledTasksForWorkflow", + query = "SELECT t FROM AssignableTask t " + "WHERE t.lockingUser = :user " + "AND t.workflow = :workflow" ) , @NamedQuery( - name = "UserTask.findAssignedTasks", - query = "SELECT t FROM UserTask t " + name = "AssignableTask.findAssignedTasks", + query = "SELECT t FROM AssignableTask t " + "WHERE t.assignments.role IN :roles " + "AND t.assignments.workflow = :workflow " + "AND t.active = true") + , + @NamedQuery( + name = "AssignableTask.findOverdueTasks", + query = "SELECT t FROM AssignableTask t " + + "WHERE t.workflow = :workflow " + + "AND t.dueDate < :now") }) //Can't reduce complexity yet @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.StdCyclomaticComplexity", "PMD.ModifiedCyclomaticComplexity"}) -public class UserTask extends Task implements Serializable { +public class AssignableTask extends Task implements Serializable { private static final long serialVersionUID = 4188064584389893019L; @@ -99,7 +105,7 @@ public class UserTask extends Task implements Serializable { @OneToMany(mappedBy = "task") private List assignments; - public UserTask() { + public AssignableTask() { super(); assignments = new ArrayList<>(); } @@ -217,10 +223,10 @@ public class UserTask extends Task implements Serializable { return false; } - if (!(obj instanceof UserTask)) { + if (!(obj instanceof AssignableTask)) { return false; } - final UserTask other = (UserTask) obj; + final AssignableTask other = (AssignableTask) obj; if (!other.canEqual(this)) { return false; } @@ -245,7 +251,7 @@ public class UserTask extends Task implements Serializable { @Override public boolean canEqual(final Object obj) { - return obj instanceof UserTask; + return obj instanceof AssignableTask; } @Override diff --git a/ccm-core/src/main/java/org/libreccm/workflow/UserTaskRepository.java b/ccm-core/src/main/java/org/libreccm/workflow/AssignableTaskRepository.java similarity index 61% rename from ccm-core/src/main/java/org/libreccm/workflow/UserTaskRepository.java rename to ccm-core/src/main/java/org/libreccm/workflow/AssignableTaskRepository.java index 5ddcf3615..6a849ba96 100644 --- a/ccm-core/src/main/java/org/libreccm/workflow/UserTaskRepository.java +++ b/ccm-core/src/main/java/org/libreccm/workflow/AssignableTaskRepository.java @@ -33,40 +33,43 @@ import javax.persistence.TypedQuery; * @author Jens Pelzetter */ @RequestScoped -public class UserTaskRepository extends AbstractEntityRepository { +public class AssignableTaskRepository + extends AbstractEntityRepository { @Override - public Class getEntityClass() { - return UserTask.class; + public Class getEntityClass() { + return AssignableTask.class; } @Override - public boolean isNew(final UserTask task) { + public boolean isNew(final AssignableTask task) { return task.getTaskId() == 0; } - public List findEnabledTasksForWorkflow(final User user, - final Workflow workflow) { - final TypedQuery query = getEntityManager().createNamedQuery( - "UserTask.findEnabledTasksForWorkflow", UserTask.class); + public List findEnabledTasksForWorkflow( + final User user, final Workflow workflow) { + final TypedQuery query = getEntityManager() + .createNamedQuery( + "UserTask.findEnabledTasksForWorkflow", AssignableTask.class); query.setParameter("user", user); query.setParameter("workflow", workflow); return query.getResultList(); } - - public List getAssignedTasks(final User user, - final Workflow workflow) { - final TypedQuery query = getEntityManager().createNamedQuery( - "UserTask.findAssignedTasks", UserTask.class); + + public List getAssignedTasks(final User user, + final Workflow workflow) { + final TypedQuery query = getEntityManager() + .createNamedQuery( + "UserTask.findAssignedTasks", AssignableTask.class); final List roles = user.getRoleMemberships() - .stream() - .map(membership -> membership.getRole()) - .collect(Collectors.toList()); - - query.setParameter("roles", roles ); + .stream() + .map(membership -> membership.getRole()) + .collect(Collectors.toList()); + + query.setParameter("roles", roles); query.setParameter("workflow", workflow); - + return query.getResultList(); } diff --git a/ccm-core/src/main/java/org/libreccm/workflow/Task.java b/ccm-core/src/main/java/org/libreccm/workflow/Task.java index d7ab81ee5..527d4c193 100644 --- a/ccm-core/src/main/java/org/libreccm/workflow/Task.java +++ b/ccm-core/src/main/java/org/libreccm/workflow/Task.java @@ -30,9 +30,10 @@ import java.util.Objects; import javax.persistence.AssociationOverride; import javax.persistence.Column; -import javax.persistence.ElementCollection; import javax.persistence.Embedded; import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @@ -40,9 +41,11 @@ import javax.persistence.Inheritance; import javax.persistence.InheritanceType; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; -import javax.persistence.Lob; import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.OneToMany; import javax.persistence.Table; /** @@ -59,6 +62,35 @@ import javax.persistence.Table; "PMD.ShortClassName", "PMD.TooManyMethods", "PMD.AvoidDuplicateLiterals"}) +@NamedQueries({ + @NamedQuery( + name = "Task.countUnfinishedAndActiveTasksForWorkflow", + query = "SELECT COUNT(t) FROM Task t " + + "WHERE t.taskState != org.libreccm.workflow.TaskState.FINISHED " + + "AND t.active = true " + + "AND t.workflow = :workflow") + , + @NamedQuery( + name = "Task.countUnfinishedTasksForWorkflow", + query = "SELECT COUNT(t) FROM Task t " + + "WHERE t.taskState != org.libreccm.workflow.TaskState.FINISHED " + + "AND t.workflow = :workflow" + ) + , + @NamedQuery( + name = "Task.findEnabledTasks", + query = "SELECT t FROM Task t " + + "WHERE t.workflow = :workflow " + + "AND t.taskState = org.libreccm.workflow.TaskState.ENABLED " + + "AND t.active = true" + ) + , + @NamedQuery( + name = "Task.findFinishedTasks", + query = "SELECT t FROM Task t " + + "WHERE t.workflow = :workflow " + + "AND t.taskState = org.libreccm.workflow.TaskState.FINISHED") +}) public class Task implements Serializable { private static final long serialVersionUID = 8161343036908150426L; @@ -70,27 +102,28 @@ public class Task implements Serializable { @Embedded @AssociationOverride( - name = "values", - joinTable = @JoinTable(name = "WORKFLOW_TASK_LABELS", - schema = DB_SCHEMA, - joinColumns = { - @JoinColumn(name = "TASK_ID")})) + name = "values", + joinTable = @JoinTable(name = "WORKFLOW_TASK_LABELS", + schema = DB_SCHEMA, + joinColumns = { + @JoinColumn(name = "TASK_ID")})) private LocalizedString label; @Embedded @AssociationOverride( - name = "values", - joinTable = @JoinTable(name = "WORKFLOW_TASKS_DESCRIPTIONS", - schema = DB_SCHEMA, - joinColumns = { - @JoinColumn(name = "TASK_ID")})) + name = "values", + joinTable = @JoinTable(name = "WORKFLOW_TASKS_DESCRIPTIONS", + schema = DB_SCHEMA, + joinColumns = { + @JoinColumn(name = "TASK_ID")})) private LocalizedString description; @Column(name = "ACTIVE") private boolean active; @Column(name = "TASK_STATE", length = 512) - private String taskState; + @Enumerated(EnumType.STRING) + private TaskState taskState; @ManyToOne @JoinColumn(name = "WORKFLOW_ID") @@ -108,14 +141,9 @@ public class Task implements Serializable { @JoinColumn(name = "DEPENDENT_TASK_ID")}) private List dependsOn; - @ElementCollection - @JoinTable(name = "WORKFLOW_TASK_COMMENTS", - schema = DB_SCHEMA, - joinColumns = { - @JoinColumn(name = "TASK_ID")}) - @Column(name = "COMMENT") - @Lob - private List comments; + @OneToMany + @JoinColumn(name = "TASK_ID") + private List comments; public Task() { super(); @@ -159,11 +187,11 @@ public class Task implements Serializable { this.active = active; } - public String getTaskState() { + public TaskState getTaskState() { return taskState; } - public void setTaskState(final String taskState) { + protected void setTaskState(final TaskState taskState) { this.taskState = taskState; } @@ -215,7 +243,7 @@ public class Task implements Serializable { dependsOn.remove(task); } - public List getComments() { + public List getComments() { if (comments == null) { return null; } else { @@ -223,15 +251,15 @@ public class Task implements Serializable { } } - protected void setComments(final List comments) { + protected void setComments(final List comments) { this.comments = comments; } - public void addComment(final String comment) { + public void addComment(final TaskComment comment) { comments.add(comment); } - public void removeComment(final String comment) { + public void removeComment(final TaskComment comment) { comments.remove(comment); } @@ -294,14 +322,14 @@ public class Task implements Serializable { public String toString(final String data) { return String.format("%s{ " - + "taskId = %d, " - + "label = %s, " - + "active = %b, " - + "taskState = \"%s\", " - + "workflow = %s, " - + "dependentTasks = %s, " - + "dependsOn = %s%s" - + " }", + + "taskId = %d, " + + "label = %s, " + + "active = %b, " + + "taskState = \"%s\", " + + "workflow = %s, " + + "dependentTasks = %s, " + + "dependsOn = %s%s" + + " }", super.toString(), taskId, Objects.toString(label), diff --git a/ccm-core/src/main/java/org/libreccm/workflow/TaskAssignment.java b/ccm-core/src/main/java/org/libreccm/workflow/TaskAssignment.java index efc8b0dd3..1d0a37bdc 100644 --- a/ccm-core/src/main/java/org/libreccm/workflow/TaskAssignment.java +++ b/ccm-core/src/main/java/org/libreccm/workflow/TaskAssignment.java @@ -51,7 +51,7 @@ public class TaskAssignment implements Serializable { @ManyToOne @JoinColumn(name = "TASK_ID") - private UserTask task; + private AssignableTask task; @ManyToOne @JoinColumn(name = "ROLE_ID") @@ -65,11 +65,11 @@ public class TaskAssignment implements Serializable { this.taskAssignmentId = taskAssignmentId; } - public UserTask getTask() { + public AssignableTask getTask() { return task; } - protected void setTask(final UserTask task) { + protected void setTask(final AssignableTask task) { this.task = task; } diff --git a/ccm-core/src/main/java/org/libreccm/workflow/Workflow.java b/ccm-core/src/main/java/org/libreccm/workflow/Workflow.java index 28fd30937..a73fde010 100644 --- a/ccm-core/src/main/java/org/libreccm/workflow/Workflow.java +++ b/ccm-core/src/main/java/org/libreccm/workflow/Workflow.java @@ -20,6 +20,7 @@ package org.libreccm.workflow; import static org.libreccm.core.CoreConstants.*; +import org.libreccm.core.CcmObject; import org.libreccm.l10n.LocalizedString; import java.io.Serializable; @@ -32,6 +33,8 @@ import javax.persistence.AssociationOverride; import javax.persistence.Column; import javax.persistence.Embedded; import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @@ -40,7 +43,10 @@ import javax.persistence.InheritanceType; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToOne; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; import javax.persistence.OneToMany; +import javax.persistence.OneToOne; import javax.persistence.Table; /** @@ -50,6 +56,12 @@ import javax.persistence.Table; @Entity @Table(name = "WORKFLOWS", schema = DB_SCHEMA) @Inheritance(strategy = InheritanceType.JOINED) +@NamedQueries({ + @NamedQuery( + name = "Workflow.findForObject", + query = "SELECT w FROM Workflow w " + + "WHERE W.object = :object") +}) public class Workflow implements Serializable { private static final long serialVersionUID = 4322500264543325829L; @@ -62,7 +74,7 @@ public class Workflow implements Serializable { @ManyToOne @JoinColumn(name = "TEMPLATE_ID") private WorkflowTemplate template; - + @Embedded @AssociationOverride( name = "values", @@ -82,6 +94,21 @@ public class Workflow implements Serializable { })) private LocalizedString description; + @Column(name = "WORKFLOW_STATE") + @Enumerated(EnumType.STRING) + private WorkflowState state; + + @Column(name = "ACTIVE") + private boolean active; + + @Column(name = "TASKS_STATE") + @Enumerated(EnumType.STRING) + private TaskState tasksState; + + @OneToOne + @JoinColumn(name = "OBJECT_ID") + private CcmObject object; + @OneToMany(mappedBy = "workflow") private List tasks; @@ -100,11 +127,11 @@ public class Workflow implements Serializable { public void setWorkflowId(final long workflowId) { this.workflowId = workflowId; } - + public WorkflowTemplate getTemplate() { return template; } - + protected void setTemplate(final WorkflowTemplate template) { this.template = template; } @@ -125,6 +152,38 @@ public class Workflow implements Serializable { this.description = description; } + public WorkflowState getState() { + return state; + } + + protected void setState(final WorkflowState state) { + this.state = state; + } + + public boolean isActive() { + return active; + } + + protected void setActive(final boolean active) { + this.active = active; + } + + public TaskState getTasksState() { + return tasksState; + } + + protected void setTasksState(final TaskState tasksState) { + this.tasksState = tasksState; + } + + public CcmObject getObject() { + return object; + } + + protected void setObject(final CcmObject object) { + this.object = object; + } + public List getTasks() { if (tasks == null) { return null; @@ -150,6 +209,11 @@ public class Workflow implements Serializable { int hash = 5; hash = 79 * hash + (int) (this.workflowId ^ (this.workflowId >>> 32)); hash = 79 * hash + Objects.hashCode(this.name); + hash = 79 * hash + Objects.hashCode(description); + hash = 79 * hash + Objects.hashCode(state); + hash = 79 * hash + (active ? 1 : 0); + hash = 79 * hash + Objects.hashCode(tasksState); + hash = 79 * hash + Objects.hashCode(object); return hash; } @@ -166,11 +230,32 @@ public class Workflow implements Serializable { return false; } - if (this.workflowId != other.getWorkflowId()) { + if (workflowId != other.getWorkflowId()) { + return false; + } + + if (!Objects.equals(name, other.getName())) { + return false; + } + + if (!Objects.equals(description, other.getDescription())) { + return false; + } + + if (!Objects.equals(state, other.getState())) { + return false; + } + + if (active != other.isActive()) { return false; } - return Objects.equals(this.name, other.getName()); + if (!Objects.equals(tasksState, other.getTasksState())) { + return false; + } + + return Objects.equals(object, other.getObject()); + } public boolean canEqual(final Object obj) { @@ -185,12 +270,20 @@ public class Workflow implements Serializable { public String toString(final String data) { return String.format("%s{ " + "workflowId = %d, " - + "name = \"%s\"%s" + + "name = \"%s\", " + + "description = \"%s\", " + + "state = \"%s\", " + + "active = %b" + + "object = \"%s\"%s" + " }", super.toString(), workflowId, - name, + Objects.toString(name), + Objects.toString(description), + Objects.toString(state), + active, + Objects.toString(object), data); } - + } diff --git a/ccm-core/src/main/java/org/libreccm/workflow/WorkflowManager.java b/ccm-core/src/main/java/org/libreccm/workflow/WorkflowManager.java index 7271c4597..642d7c486 100644 --- a/ccm-core/src/main/java/org/libreccm/workflow/WorkflowManager.java +++ b/ccm-core/src/main/java/org/libreccm/workflow/WorkflowManager.java @@ -18,14 +18,17 @@ */ package org.libreccm.workflow; +import com.arsdigita.kernel.KernelConfig; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.libreccm.configuration.ConfigurationManager; +import org.libreccm.core.CcmObject; import org.libreccm.core.CoreConstants; import org.libreccm.l10n.LocalizedString; import org.libreccm.security.AuthorizationRequired; import org.libreccm.security.RequiresPrivilege; -import org.libreccm.security.Role; -import org.libreccm.security.RoleRepository; import org.libreccm.security.Shiro; -import org.libreccm.security.User; import java.beans.BeanInfo; import java.beans.IntrospectionException; @@ -33,12 +36,14 @@ import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; +import javax.annotation.PostConstruct; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.persistence.EntityManager; @@ -52,6 +57,9 @@ import javax.transaction.Transactional; @RequestScoped public class WorkflowManager { + private final static Logger LOGGER = LogManager.getLogger( + WorkflowManager.class); + @Inject private EntityManager entityManager; @@ -62,15 +70,28 @@ public class WorkflowManager { private TaskRepository taskRepo; @Inject - private RoleRepository roleRepo; + private TaskManager taskManager; @Inject private Shiro shiro; + @Inject + private ConfigurationManager confManager; + + private Locale defaultLocale; + + @PostConstruct + private void init() { + final KernelConfig kernelConfig = confManager.findConfiguration( + KernelConfig.class); + defaultLocale = kernelConfig.getDefaultLocale(); + } + @AuthorizationRequired @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @Transactional(Transactional.TxType.REQUIRED) - public Workflow createWorkflow(final WorkflowTemplate template) { + public Workflow createWorkflow(final WorkflowTemplate template, + final CcmObject object) { final Workflow workflow = new Workflow(); final LocalizedString name = new LocalizedString(); @@ -90,6 +111,9 @@ public class WorkflowManager { template.getTasks().forEach(taskTemplate -> fixTaskDependencies( taskTemplate, tasks.get(taskTemplate.getTaskId()), tasks)); + workflow.setObject(object); + workflow.setState(WorkflowState.INIT); + tasks.values().forEach(task -> taskRepo.save(task)); workflowRepo.save(workflow); @@ -172,139 +196,161 @@ public class WorkflowManager { @AuthorizationRequired @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @Transactional(Transactional.TxType.REQUIRED) - public void addTask(final Workflow workflow, final Task task) { - workflow.addTask(task); - task.setWorkflow(workflow); - - workflowRepo.save(workflow); - taskRepo.save(task); - } - - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - @Transactional(Transactional.TxType.REQUIRED) - public void removeTask(final Workflow workflow, final Task task) { - workflow.removeTask(task); - task.setWorkflow(null); - - workflowRepo.save(workflow); - taskRepo.save(task); - } - - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - @Transactional(Transactional.TxType.REQUIRED) - public void assignTask(final UserTask task, final Role role) { - final TaskAssignment assignment = new TaskAssignment(); - assignment.setTask(task); - assignment.setRole(role); - - task.addAssignment(assignment); - role.addAssignedTask(assignment); - - entityManager.persist(assignment); - taskRepo.save(task); - roleRepo.save(role); - } - - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - @Transactional(Transactional.TxType.REQUIRED) - public void retractTask(final UserTask task, final Role role) { - final List result = task.getAssignments().stream() - .filter(assigned -> role.equals(assigned.getRole())) - .collect(Collectors.toList()); - - if (!result.isEmpty()) { - final TaskAssignment assignment = result.get(0); - task.removeAssignment(assignment); - role.removeAssignedTask(assignment); - entityManager.remove(assignment); + public List findEnabledTasks(final Workflow workflow) { + if (workflow.getState() == WorkflowState.DELETED + || workflow.getState() == WorkflowState.STOPPED) { + LOGGER.debug(String.format("Workflow state is \"%s\". Workflow " + + "has no enabled tasks.", + workflow.getState().toString())); + return Collections.emptyList(); } + + final TypedQuery query = entityManager.createNamedQuery( + "Task.findEnabledTasks", Task.class); + query.setParameter("workflow", workflow); + + return Collections.unmodifiableList(query.getResultList()); } @AuthorizationRequired @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @Transactional(Transactional.TxType.REQUIRED) - public void addDependentTask(final Task parent, final Task task) { - parent.addDependentTask(task); - task.addDependsOn(parent); + public List findFinishedTasks(final Workflow workflow) { + final TypedQuery query = entityManager.createNamedQuery( + "Task.findFinishedTasks", Task.class); + query.setParameter("workflow", workflow); - taskRepo.save(task); - taskRepo.save(parent); + return Collections.unmodifiableList(query.getResultList()); } @AuthorizationRequired @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @Transactional(Transactional.TxType.REQUIRED) - public void removeDependentTask(final Task parent, final Task task) { - parent.removeDependentTask(task); - task.removeDependsOn(parent); + public List findOverdueTasks(final Workflow workflow) { + final TypedQuery query = entityManager.createNamedQuery( + "AssignableTask.findOverdueTasks", AssignableTask.class); + query.setParameter("workflow", workflow); + query.setParameter("now", new Date()); - taskRepo.save(task); - taskRepo.save(parent); + return Collections.unmodifiableList(query.getResultList()); } @AuthorizationRequired @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @Transactional(Transactional.TxType.REQUIRED) - public void lockTask(final UserTask task) { - task.setLocked(true); - task.setLockingUser(shiro.getUser()); - - taskRepo.save(task); - } - - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - @Transactional(Transactional.TxType.REQUIRED) - public void unlockTask(final UserTask task) { - task.setLocked(false); - task.setLockingUser(null); - - taskRepo.save(task); - } - - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - @Transactional(Transactional.TxType.REQUIRED) - public List lockedBy(final User user) { - final TypedQuery query = entityManager.createNamedQuery( - "UserTask.findLockedBy", UserTask.class); - query.setParameter("user", user); - - return query.getResultList(); - } - public void start(final Workflow workflow) { - if (workflow.getTasks() != null && !workflow.getTasks().isEmpty()) { - final Task first = workflow.getTasks().get(0); + final WorkflowState oldState = workflow.getState(); - if (first instanceof UserTask) { - final User user = shiro.getUser(); - lockTask((UserTask) first); + workflow.setState(WorkflowState.STARTED); + if (oldState == WorkflowState.INIT) { + workflow.setActive(true); + updateState(workflow); + + for (final Task current : workflow.getTasks()) { + current.setActive(true); + taskManager.updateState(current); + } + } + + workflowRepo.save(workflow); + } + + @AuthorizationRequired + @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) + @Transactional(Transactional.TxType.REQUIRED) + private void updateState(final Workflow workflow) { + if (workflow.getTasksState() == TaskState.ENABLED) { + final TypedQuery query = entityManager.createNamedQuery( + "Task.countUnfinishedAndActiveTasksForWorkflow", Long.class); + query.setParameter("workflow", workflow); + + final Long result = query.getSingleResult(); + + if (result > 0) { + return; + } else { + finish(workflow); + } + } + + if (workflow.getTasksState() == TaskState.FINISHED) { + final TypedQuery query = entityManager.createNamedQuery( + "Task.countUnfinishedTasksForWorkflow", Long.class); + query.setParameter("workflow", workflow); + + final Long result = query.getSingleResult(); + + if (result > 0) { + enable(workflow); } } } - /** - * Gets the state of a workflow. - * - * @param workflow - * @return - */ - public int getState(final Workflow workflow) { + @AuthorizationRequired + @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) + @Transactional(Transactional.TxType.REQUIRED) + public void stop(final Workflow workflow) { + workflow.setState(WorkflowState.STOPPED); + workflowRepo.save(workflow); + } - final Optional activeTask = workflow.getTasks() - .stream() - .filter(task -> task.isActive()) - .findAny(); + @AuthorizationRequired + @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) + @Transactional(Transactional.TxType.REQUIRED) + public void finish(final Workflow workflow) { + if (workflow.getTasksState() != TaskState.ENABLED) { + throw new IllegalArgumentException(String.format( + "Workflow \"%s\" is not enabled.", + workflow.getName().getValue(defaultLocale))); + } - if (activeTask.isPresent()) { - return WorkflowConstants.STARTED; - } else { - return -1; + workflow.setTasksState(TaskState.FINISHED); + workflowRepo.save(workflow); + + } + + @AuthorizationRequired + @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) + @Transactional(Transactional.TxType.REQUIRED) + public void enable(final Workflow workflow) { + if (workflow.getTasksState() == TaskState.ENABLED) { + return; + } + + switch (workflow.getTasksState()) { + case DISABLED: + LOGGER.debug("Workflow \"{}\" is disabled; enabling it.", + workflow.getName().getValue(defaultLocale)); + workflow.setTasksState(TaskState.ENABLED); + workflowRepo.save(workflow); + break; + case FINISHED: + LOGGER.debug("Workflow \"{}\" is finished; reenabling it."); + workflow.setTasksState(TaskState.ENABLED); + workflowRepo.save(workflow); + break; + default: + LOGGER.debug("Workflow \"{}\" has tasksState \"{}\", " + + "#enable(Workflow) does nothing.", + workflow.getName().getValue(defaultLocale), + workflow.getTasksState()); + break; } } + @AuthorizationRequired + @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) + @Transactional(Transactional.TxType.REQUIRED) + public void disable(final Workflow workflow) { + if (workflow.getTasksState() == TaskState.DISABLED) { + return; + } + + workflow.setTasksState(TaskState.DISABLED); + workflowRepo.save(workflow); + + workflow.getTasks().forEach(task -> taskManager.disable(task)); + workflow.setState(WorkflowState.INIT); + } + } diff --git a/ccm-core/src/main/java/org/libreccm/workflow/WorkflowRepository.java b/ccm-core/src/main/java/org/libreccm/workflow/WorkflowRepository.java index 212d760c5..a09f2918c 100644 --- a/ccm-core/src/main/java/org/libreccm/workflow/WorkflowRepository.java +++ b/ccm-core/src/main/java/org/libreccm/workflow/WorkflowRepository.java @@ -19,8 +19,13 @@ package org.libreccm.workflow; import org.libreccm.core.AbstractEntityRepository; +import org.libreccm.core.CcmObject; + +import java.util.Optional; import javax.enterprise.context.RequestScoped; +import javax.persistence.NoResultException; +import javax.persistence.TypedQuery; /** * @@ -39,4 +44,21 @@ public class WorkflowRepository extends AbstractEntityRepository return workflow.getWorkflowId() == 0; } + public Optional findWorkflowForObject(final CcmObject object) { + if (object == null) { + throw new IllegalArgumentException( + "Can't find a workflow for object null."); + } + + final TypedQuery query = getEntityManager().createNamedQuery( + "Workflow.findForObject", Workflow.class); + query.setParameter("object", object); + + try { + return Optional.of(query.getSingleResult()); + } catch(NoResultException ex) { + return Optional.empty(); + } + } + } diff --git a/ccm-core/src/main/java/org/libreccm/workflow/WorkflowTemplate.java b/ccm-core/src/main/java/org/libreccm/workflow/WorkflowTemplate.java index 7ff233d2c..1bbd3f39e 100644 --- a/ccm-core/src/main/java/org/libreccm/workflow/WorkflowTemplate.java +++ b/ccm-core/src/main/java/org/libreccm/workflow/WorkflowTemplate.java @@ -20,6 +20,8 @@ package org.libreccm.workflow; import static org.libreccm.core.CoreConstants.*; +import org.libreccm.core.CcmObject; + import java.io.Serializable; import javax.persistence.Entity; @@ -35,6 +37,12 @@ public class WorkflowTemplate extends Workflow implements Serializable { private static final long serialVersionUID = 5770519379144947171L; + @Override + protected void setObject(final CcmObject object) { + throw new UnsupportedOperationException( + "A WorkflowTemplate has no object."); + } + @Override public int hashCode() { return super.hashCode(); diff --git a/ccm-core/src/test/java/org/libreccm/security/EqualsAndHashCodeTest.java b/ccm-core/src/test/java/org/libreccm/security/EqualsAndHashCodeTest.java index c48b2c270..edc7833f0 100644 --- a/ccm-core/src/test/java/org/libreccm/security/EqualsAndHashCodeTest.java +++ b/ccm-core/src/test/java/org/libreccm/security/EqualsAndHashCodeTest.java @@ -23,7 +23,7 @@ import org.junit.runners.Parameterized; import org.libreccm.core.CcmObject; import org.libreccm.tests.categories.UnitTest; import org.libreccm.testutils.EqualsVerifier; -import org.libreccm.workflow.UserTask; +import org.libreccm.workflow.AssignableTask; import java.util.Arrays; import java.util.Collection; @@ -88,10 +88,10 @@ public class EqualsAndHashCodeTest extends EqualsVerifier { ccmObject1.setObjectId(-200); ccmObject1.setDisplayName("Object 2"); - final UserTask task1 = new UserTask(); + final AssignableTask task1 = new AssignableTask(); task1.setTaskId(-10); - final UserTask task2 = new UserTask(); + final AssignableTask task2 = new AssignableTask(); task2.setTaskId(-20); verifier @@ -100,7 +100,7 @@ public class EqualsAndHashCodeTest extends EqualsVerifier { .withPrefabValues(Role.class, role1, role2) .withPrefabValues(Party.class, party1, party2) .withPrefabValues(CcmObject.class, ccmObject1, ccmObject2) - .withPrefabValues(UserTask.class, task1, task2); + .withPrefabValues(AssignableTask.class, task1, task2); } } diff --git a/ccm-core/src/test/java/org/libreccm/workflow/EqualsAndHashCodeTest.java b/ccm-core/src/test/java/org/libreccm/workflow/EqualsAndHashCodeTest.java index 0e7303b87..658f4f1bf 100644 --- a/ccm-core/src/test/java/org/libreccm/workflow/EqualsAndHashCodeTest.java +++ b/ccm-core/src/test/java/org/libreccm/workflow/EqualsAndHashCodeTest.java @@ -21,6 +21,7 @@ package org.libreccm.workflow; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import org.libreccm.core.CcmObject; import org.libreccm.security.Group; import org.libreccm.security.Role; import org.libreccm.security.User; @@ -43,8 +44,9 @@ public class EqualsAndHashCodeTest extends EqualsVerifier { public static Collection> data() { return Arrays.asList(new Class[]{ Task.class, + TaskComment.class, TaskAssignment.class, - UserTask.class, + AssignableTask.class, Workflow.class, WorkflowTemplate.class }); @@ -53,59 +55,73 @@ public class EqualsAndHashCodeTest extends EqualsVerifier { public EqualsAndHashCodeTest(final Class entityClass) { super(entityClass); } - + @Override protected void addPrefabValues( final nl.jqno.equalsverifier.EqualsVerifier verifier) { - + super.addPrefabValues(verifier); - - final UserTask userTask1 = new UserTask(); + + final AssignableTask userTask1 = new AssignableTask(); userTask1.setTaskId(-10); - - final UserTask userTask2 = new UserTask(); + + final AssignableTask userTask2 = new AssignableTask(); userTask2.setTaskId(-20); - + final Role role1 = new Role(); role1.setName("role1"); - + final Role role2 = new Role(); role2.setName("role2"); - + final Task task1 = new Task(); task1.setTaskId(-10); - - final Task task2 = new Task(); + + final Task task2 = new Task(); task2.setTaskId(-20); - + final Group group1 = new Group(); group1.setName("group1"); - + final Group group2 = new Group(); group2.setName("group2"); - + final User user1 = new TestUser(); user1.setName("user1"); - + final User user2 = new TestUser(); user2.setName("user2"); - + + final Workflow workflow1 = new Workflow(); + workflow1.getName().addValue(Locale.ENGLISH, "Workflow 1"); + + final Workflow workflow2 = new Workflow(); + workflow2.getName().addValue(Locale.ENGLISH, "Workflow 2"); + final WorkflowTemplate template1 = new WorkflowTemplate(); template1.getName().addValue(Locale.ENGLISH, "Template 1"); - + final WorkflowTemplate template2 = new WorkflowTemplate(); template1.getName().addValue(Locale.ENGLISH, "Template 2"); + final CcmObject object1 = new CcmObject(); + object1.setDisplayName("Object 1"); + + final CcmObject object2 = new CcmObject(); + object2.setDisplayName("Object 2"); + verifier - .withPrefabValues(UserTask.class, userTask1, userTask2) + .withPrefabValues(AssignableTask.class, userTask1, userTask2) .withPrefabValues(Role.class, role1, role2) .withPrefabValues(Task.class, task1, task2) .withPrefabValues(Group.class, group1, group2) .withPrefabValues(User.class, user1, user2) - .withPrefabValues(WorkflowTemplate.class, template1, template2); + .withPrefabValues(Workflow.class, workflow1, workflow2) + .withPrefabValues(WorkflowTemplate.class, template1, template2) + .withPrefabValues(CcmObject.class, object1, object2); } - - /** + + /** * {@link User} has a protected constructor, so have have do this to create * users for the test... */ diff --git a/ccm-core/src/test/java/org/libreccm/workflow/ToStringTest.java b/ccm-core/src/test/java/org/libreccm/workflow/ToStringTest.java index 1c8fa5644..438f46909 100644 --- a/ccm-core/src/test/java/org/libreccm/workflow/ToStringTest.java +++ b/ccm-core/src/test/java/org/libreccm/workflow/ToStringTest.java @@ -40,7 +40,7 @@ public class ToStringTest extends ToStringVerifier { return Arrays.asList(new Class[]{ Task.class, TaskAssignment.class, - UserTask.class, + AssignableTask.class, Workflow.class }); } diff --git a/ccm-core/src/test/resources-wildfly-remote-h2-mem/scripts/create_ccm_core_schema.sql b/ccm-core/src/test/resources-wildfly-remote-h2-mem/scripts/create_ccm_core_schema.sql index 7ff2e46a5..8f62fd7ed 100644 --- a/ccm-core/src/test/resources-wildfly-remote-h2-mem/scripts/create_ccm_core_schema.sql +++ b/ccm-core/src/test/resources-wildfly-remote-h2-mem/scripts/create_ccm_core_schema.sql @@ -1,9 +1,3 @@ -DROP SCHEMA IF EXISTS ccm_core; - -DROP SEQUENCE IF EXISTS hibernate_sequence; - -CREATE SCHEMA ccm_core; - create table CCM_CORE.APPLICATIONS ( APPLICATION_TYPE varchar(1024) not null, @@ -500,8 +494,8 @@ CREATE SCHEMA ccm_core; NAME varchar(512) not null, SETTING_VALUE_DOUBLE double, SETTING_VALUE_BOOLEAN boolean, - SETTING_VALUE_BIG_DECIMAL decimal(19,2), SETTING_VALUE_LONG bigint, + SETTING_VALUE_BIG_DECIMAL decimal(19,2), SETTING_VALUE_STRING varchar(1024), primary key (SETTING_ID) ); @@ -556,6 +550,17 @@ CREATE SCHEMA ccm_core; primary key (PARTY_ID) ); + create table CCM_CORE.WORKFLOW_ASSIGNABLE_TASKS ( + DUE_DATE timestamp, + DURATION_MINUTES bigint, + LOCKED boolean, + START_DATE timestamp, + TASK_ID bigint not null, + LOCKING_USER_ID bigint, + NOTIFICATION_SENDER bigint, + primary key (TASK_ID) + ); + create table CCM_CORE.WORKFLOW_DESCRIPTIONS ( WORKFLOW_ID bigint not null, LOCALIZED_VALUE longvarchar, @@ -571,8 +576,11 @@ CREATE SCHEMA ccm_core; ); create table CCM_CORE.WORKFLOW_TASK_COMMENTS ( - TASK_ID bigint not null, - COMMENT clob + COMMENT_ID bigint not null, + COMMENT longvarchar, + AUTHOR_ID bigint, + TASK_ID bigint, + primary key (COMMENT_ID) ); create table CCM_CORE.WORKFLOW_TASK_DEPENDENCIES ( @@ -607,19 +615,11 @@ CREATE SCHEMA ccm_core; primary key (WORKFLOW_ID) ); - create table CCM_CORE.WORKFLOW_USER_TASKS ( - DUE_DATE timestamp, - DURATION_MINUTES bigint, - LOCKED boolean, - START_DATE timestamp, - TASK_ID bigint not null, - LOCKING_USER_ID bigint, - NOTIFICATION_SENDER bigint, - primary key (TASK_ID) - ); - create table CCM_CORE.WORKFLOWS ( WORKFLOW_ID bigint not null, + ACTIVE boolean, + WORKFLOW_STATE varchar(255), + OBJECT_ID bigint, TEMPLATE_ID bigint, primary key (WORKFLOW_ID) ); @@ -1054,9 +1054,9 @@ create sequence hibernate_sequence start with 1 increment by 1; references CCM_CORE.CCM_ROLES; alter table CCM_CORE.TASK_ASSIGNMENTS - add constraint FKc1vovbjg9mp5yegx2fdoutx7u + add constraint FKk6gl2yvqr7gnqq25s1bm2gy4i foreign key (TASK_ID) - references CCM_CORE.WORKFLOW_USER_TASKS; + references CCM_CORE.WORKFLOW_ASSIGNABLE_TASKS; alter table CCM_CORE.THREADS add constraint FKsx08mpwvwnw97uwdgjs76q39g @@ -1078,6 +1078,21 @@ create sequence hibernate_sequence start with 1 increment by 1; foreign key (PARTY_ID) references CCM_CORE.PARTIES; + alter table CCM_CORE.WORKFLOW_ASSIGNABLE_TASKS + add constraint FK1pnsq9ur3ylq0ghuj23p4cogs + foreign key (LOCKING_USER_ID) + references CCM_CORE.USERS; + + alter table CCM_CORE.WORKFLOW_ASSIGNABLE_TASKS + add constraint FK9ngp088m8xa82swy7yg3qx6vh + foreign key (NOTIFICATION_SENDER) + references CCM_CORE.USERS; + + alter table CCM_CORE.WORKFLOW_ASSIGNABLE_TASKS + add constraint FKt9ha3no3bj8a50pnw8cnqh2cq + foreign key (TASK_ID) + references CCM_CORE.WORKFLOW_TASKS; + alter table CCM_CORE.WORKFLOW_DESCRIPTIONS add constraint FKgx7upkqky82dpxvbs95imfl9l foreign key (WORKFLOW_ID) @@ -1088,6 +1103,11 @@ create sequence hibernate_sequence start with 1 increment by 1; foreign key (WORKFLOW_ID) references CCM_CORE.WORKFLOWS; + alter table CCM_CORE.WORKFLOW_TASK_COMMENTS + add constraint FKd2ymdg8nay9pmh2nn2whba0j8 + foreign key (AUTHOR_ID) + references CCM_CORE.USERS; + alter table CCM_CORE.WORKFLOW_TASK_COMMENTS add constraint FKkfqrf9jdvm7livu5if06w0r5t foreign key (TASK_ID) @@ -1123,20 +1143,10 @@ create sequence hibernate_sequence start with 1 increment by 1; foreign key (WORKFLOW_ID) references CCM_CORE.WORKFLOWS; - alter table CCM_CORE.WORKFLOW_USER_TASKS - add constraint FKf09depwj5rgso2dair07vnu33 - foreign key (LOCKING_USER_ID) - references CCM_CORE.USERS; - - alter table CCM_CORE.WORKFLOW_USER_TASKS - add constraint FK6evo9y34awhdfcyl8gv78qb7f - foreign key (NOTIFICATION_SENDER) - references CCM_CORE.USERS; - - alter table CCM_CORE.WORKFLOW_USER_TASKS - add constraint FKefpdf9ojplu7loo31hfm0wl2h - foreign key (TASK_ID) - references CCM_CORE.WORKFLOW_TASKS; + alter table CCM_CORE.WORKFLOWS + add constraint FKrm2yfrs6veoxoy304upq2wc64 + foreign key (OBJECT_ID) + references CCM_CORE.CCM_OBJECTS; alter table CCM_CORE.WORKFLOWS add constraint FKeixdxau4jebw682gd49tdbsjy diff --git a/ccm-core/src/test/resources-wildfly-remote-pgsql/scripts/create_ccm_core_schema.sql b/ccm-core/src/test/resources-wildfly-remote-pgsql/scripts/create_ccm_core_schema.sql index e5bf60ae8..6d9690644 100644 --- a/ccm-core/src/test/resources-wildfly-remote-pgsql/scripts/create_ccm_core_schema.sql +++ b/ccm-core/src/test/resources-wildfly-remote-pgsql/scripts/create_ccm_core_schema.sql @@ -1,8 +1,3 @@ -DROP SCHEMA IF EXISTS ccm_core CASCADE; - -DROP SEQUENCE IF EXISTS hibernate_sequence; - -CREATE SCHEMA ccm_core; create table CCM_CORE.APPLICATIONS ( APPLICATION_TYPE varchar(1024) not null, @@ -499,8 +494,8 @@ CREATE SCHEMA ccm_core; NAME varchar(512) not null, SETTING_VALUE_DOUBLE float8, SETTING_VALUE_BOOLEAN boolean, - SETTING_VALUE_BIG_DECIMAL numeric(19, 2), SETTING_VALUE_LONG int8, + SETTING_VALUE_BIG_DECIMAL numeric(19, 2), SETTING_VALUE_STRING varchar(1024), primary key (SETTING_ID) ); @@ -555,6 +550,17 @@ CREATE SCHEMA ccm_core; primary key (PARTY_ID) ); + create table CCM_CORE.WORKFLOW_ASSIGNABLE_TASKS ( + DUE_DATE timestamp, + DURATION_MINUTES int8, + LOCKED boolean, + START_DATE timestamp, + TASK_ID int8 not null, + LOCKING_USER_ID int8, + NOTIFICATION_SENDER int8, + primary key (TASK_ID) + ); + create table CCM_CORE.WORKFLOW_DESCRIPTIONS ( WORKFLOW_ID int8 not null, LOCALIZED_VALUE text, @@ -570,8 +576,11 @@ CREATE SCHEMA ccm_core; ); create table CCM_CORE.WORKFLOW_TASK_COMMENTS ( - TASK_ID int8 not null, - COMMENT text + COMMENT_ID int8 not null, + COMMENT text, + AUTHOR_ID int8, + TASK_ID int8, + primary key (COMMENT_ID) ); create table CCM_CORE.WORKFLOW_TASK_DEPENDENCIES ( @@ -606,19 +615,11 @@ CREATE SCHEMA ccm_core; primary key (WORKFLOW_ID) ); - create table CCM_CORE.WORKFLOW_USER_TASKS ( - DUE_DATE timestamp, - DURATION_MINUTES int8, - LOCKED boolean, - START_DATE timestamp, - TASK_ID int8 not null, - LOCKING_USER_ID int8, - NOTIFICATION_SENDER int8, - primary key (TASK_ID) - ); - create table CCM_CORE.WORKFLOWS ( WORKFLOW_ID int8 not null, + ACTIVE boolean, + WORKFLOW_STATE varchar(255), + OBJECT_ID int8, TEMPLATE_ID int8, primary key (WORKFLOW_ID) ); @@ -1053,9 +1054,9 @@ create sequence hibernate_sequence start 1 increment 1; references CCM_CORE.CCM_ROLES; alter table CCM_CORE.TASK_ASSIGNMENTS - add constraint FKc1vovbjg9mp5yegx2fdoutx7u + add constraint FKk6gl2yvqr7gnqq25s1bm2gy4i foreign key (TASK_ID) - references CCM_CORE.WORKFLOW_USER_TASKS; + references CCM_CORE.WORKFLOW_ASSIGNABLE_TASKS; alter table CCM_CORE.THREADS add constraint FKsx08mpwvwnw97uwdgjs76q39g @@ -1077,6 +1078,21 @@ create sequence hibernate_sequence start 1 increment 1; foreign key (PARTY_ID) references CCM_CORE.PARTIES; + alter table CCM_CORE.WORKFLOW_ASSIGNABLE_TASKS + add constraint FK1pnsq9ur3ylq0ghuj23p4cogs + foreign key (LOCKING_USER_ID) + references CCM_CORE.USERS; + + alter table CCM_CORE.WORKFLOW_ASSIGNABLE_TASKS + add constraint FK9ngp088m8xa82swy7yg3qx6vh + foreign key (NOTIFICATION_SENDER) + references CCM_CORE.USERS; + + alter table CCM_CORE.WORKFLOW_ASSIGNABLE_TASKS + add constraint FKt9ha3no3bj8a50pnw8cnqh2cq + foreign key (TASK_ID) + references CCM_CORE.WORKFLOW_TASKS; + alter table CCM_CORE.WORKFLOW_DESCRIPTIONS add constraint FKgx7upkqky82dpxvbs95imfl9l foreign key (WORKFLOW_ID) @@ -1087,6 +1103,11 @@ create sequence hibernate_sequence start 1 increment 1; foreign key (WORKFLOW_ID) references CCM_CORE.WORKFLOWS; + alter table CCM_CORE.WORKFLOW_TASK_COMMENTS + add constraint FKd2ymdg8nay9pmh2nn2whba0j8 + foreign key (AUTHOR_ID) + references CCM_CORE.USERS; + alter table CCM_CORE.WORKFLOW_TASK_COMMENTS add constraint FKkfqrf9jdvm7livu5if06w0r5t foreign key (TASK_ID) @@ -1122,20 +1143,10 @@ create sequence hibernate_sequence start 1 increment 1; foreign key (WORKFLOW_ID) references CCM_CORE.WORKFLOWS; - alter table CCM_CORE.WORKFLOW_USER_TASKS - add constraint FKf09depwj5rgso2dair07vnu33 - foreign key (LOCKING_USER_ID) - references CCM_CORE.USERS; - - alter table CCM_CORE.WORKFLOW_USER_TASKS - add constraint FK6evo9y34awhdfcyl8gv78qb7f - foreign key (NOTIFICATION_SENDER) - references CCM_CORE.USERS; - - alter table CCM_CORE.WORKFLOW_USER_TASKS - add constraint FKefpdf9ojplu7loo31hfm0wl2h - foreign key (TASK_ID) - references CCM_CORE.WORKFLOW_TASKS; + alter table CCM_CORE.WORKFLOWS + add constraint FKrm2yfrs6veoxoy304upq2wc64 + foreign key (OBJECT_ID) + references CCM_CORE.CCM_OBJECTS; alter table CCM_CORE.WORKFLOWS add constraint FKeixdxau4jebw682gd49tdbsjy