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
pull/2/head
jensp 2016-11-16 18:37:08 +00:00
parent 7430901acc
commit 48dea0fb14
44 changed files with 1548 additions and 1112 deletions

View File

@ -436,7 +436,7 @@ public class ContentItemPage extends CMSPage implements ActionListener {
* @param itemId the id of the ContentItem object to display * @param itemId the id of the ContentItem object to display
* @param tab The index of the tab 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 = final ContentItem item =
(ContentItem) DomainObjectFactory.newInstance(new OID( (ContentItem) DomainObjectFactory.newInstance(new OID(
ContentItem.BASE_DATA_OBJECT_TYPE, itemId)); ContentItem.BASE_DATA_OBJECT_TYPE, itemId));

View File

@ -57,7 +57,7 @@ import com.arsdigita.toolbox.ui.Section;
import com.arsdigita.util.Assert; import com.arsdigita.util.Assert;
import com.arsdigita.util.SequentialMap; import com.arsdigita.util.SequentialMap;
import com.arsdigita.util.UncheckedWrapperException; 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.Constructor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -66,6 +66,9 @@ import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; 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 * 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 * This constructor will be called when the component is automatically
* instantiated by the <code>AuthoringKitWizard</code>.</p> * instantiated by the <code>AuthoringKitWizard</code>.</p>
* *
* @version $Id: AuthoringKitWizard.java 2140 2011-01-16 12:04:20Z pboy $
*/ */
public class AuthoringKitWizard extends LayoutPanel implements Resettable { public class AuthoringKitWizard extends LayoutPanel implements Resettable {
/** Private Logger instance for this class */ /** Private Logger instance for this class */
private static final Logger s_log = Logger.getLogger( private static final Logger LOGGER = LogManager.getLogger(
AuthoringKitWizard.class); AuthoringKitWizard.class);
private static Class[] s_args = new Class[]{ private static Class[] s_args = new Class[]{
ItemSelectionModel.class, ItemSelectionModel.class,
@ -103,8 +105,8 @@ public class AuthoringKitWizard extends LayoutPanel implements Resettable {
private static final java.util.List<AssetStepEntry> s_assets = new private static final java.util.List<AssetStepEntry> s_assets = new
ArrayList<AssetStepEntry>(); ArrayList<AssetStepEntry>();
private final Object[] m_vals; private final Object[] m_vals;
private final ContentType m_type; private final ContentTypeInfo m_type;
private final AuthoringKit m_kit; private final AuthoringKitInfo m_kit;
private final ItemSelectionModel m_sel; private final ItemSelectionModel m_sel;
private final WorkflowRequestLocal m_workflow; private final WorkflowRequestLocal m_workflow;
private final AssignedTaskTable m_tasks; 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 * @param type The content type of the items that this wizard will
* handle * handle
* * @param model
* @param itemModel The item selection model which will supply
* this wizard with the content item object
*/ */
public AuthoringKitWizard(final ContentType type, public AuthoringKitWizard(final ContentTypeInfo type,
final ItemSelectionModel model) { final ItemSelectionModel model) {
if (s_log.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
s_log.debug("Authoring kit wizard for type " + type + " " LOGGER.debug("Authoring kit wizard for type " + type + " "
+ "undergoing creation"); + "undergoing creation");
} }
@ -262,9 +262,9 @@ public class AuthoringKitWizard extends LayoutPanel implements Resettable {
Collection skipSteps = ContentSection.getConfig().getAssetStepsToSkip( Collection skipSteps = ContentSection.getConfig().getAssetStepsToSkip(
type); type);
Iterator it = skipSteps.iterator(); Iterator it = skipSteps.iterator();
if (s_log.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
while (it.hasNext()) { while (it.hasNext()) {
s_log.debug("skip step " + it.next()); LOGGER.debug("skip step " + it.next());
} }
} }
//Iterator assets = s_assets.iterator(); //Iterator assets = s_assets.iterator();
@ -276,7 +276,7 @@ public class AuthoringKitWizard extends LayoutPanel implements Resettable {
final String baseObjectType = data.getBaseDataObjectType(); final String baseObjectType = data.getBaseDataObjectType();
//Class step = (Class) data[1]; //Class step = (Class) data[1];
Class step = data.getStep(); 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())) { if (!skipSteps.contains(step.getName())) {
//GlobalizedMessage label = (GlobalizedMessage) data[2]; //GlobalizedMessage label = (GlobalizedMessage) data[2];
GlobalizedMessage label = data.getLabel(); 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 // 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 // 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 // runs after original ccm-ldn-image-step initializer and override the registered step here
s_log.debug( LOGGER.debug(
"registering asset step - label: " "registering asset step - label: "
+ label.localize() + label.localize()
+ " step class: " + " step class: "
@ -451,7 +451,7 @@ public class AuthoringKitWizard extends LayoutPanel implements Resettable {
*/ */
if ((thisObjectType.equals(baseObjectType)) if ((thisObjectType.equals(baseObjectType))
&& (thisLabel.localize().equals(label.localize()))) { && (thisLabel.localize().equals(label.localize()))) {
s_log.debug( LOGGER.debug(
"registering authoring step with same label as previously registered step"); "registering authoring step with same label as previously registered step");
s_assets.remove(data); s_assets.remove(data);
break; break;
@ -570,8 +570,8 @@ public class AuthoringKitWizard extends LayoutPanel implements Resettable {
* @param className The Java class name of the step * @param className The Java class name of the step
*/ */
protected Component instantiateStep(String name) { protected Component instantiateStep(String name) {
if (s_log.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
s_log.debug("Instantiating kit wizard '" + name + "' with " LOGGER.debug("Instantiating kit wizard '" + name + "' with "
+ "arguments " + s_args); + "arguments " + s_args);
} }

View File

@ -18,7 +18,6 @@
*/ */
package com.arsdigita.cms.ui.authoring; package com.arsdigita.cms.ui.authoring;
import com.arsdigita.bebop.Component; import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.PageState; import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.Resettable; import com.arsdigita.bebop.Resettable;
@ -33,6 +32,7 @@ import org.librecms.contentsection.ContentType;
import com.arsdigita.cms.ItemSelectionModel; import com.arsdigita.cms.ItemSelectionModel;
import com.arsdigita.toolbox.ui.LayoutPanel; import com.arsdigita.toolbox.ui.LayoutPanel;
import com.arsdigita.util.UncheckedWrapperException;
import com.arsdigita.xml.Element; import com.arsdigita.xml.Element;
import oracle.jrockit.jfr.events.ContentTypeImpl; import oracle.jrockit.jfr.events.ContentTypeImpl;
@ -42,15 +42,14 @@ import org.librecms.contenttypes.ContentTypeInfo;
import java.math.BigDecimal; import java.math.BigDecimal;
/** /**
* An invisible component which contains all the possible authoring kits. * An invisible component which contains all the possible authoring kits. The
* The kits are loaded from the database at construction time. The selector * kits are loaded from the database at construction time. The selector chooses
* chooses which kit to display at page rendering time based on the value * which kit to display at page rendering time based on the value of the
* of the content_type state parameter. * content_type state parameter.
* *
* Essentially, this component is a hack which is used to get around * Essentially, this component is a hack which is used to get around the fact
* the fact that we cannot instantiate stateful components dynamically. * that we cannot instantiate stateful components dynamically.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
* @author unknown * @author unknown
@ -61,14 +60,14 @@ public class WizardSelector extends AuthoringKitSelector
private ItemSelectionModel itemSelectionModel; private ItemSelectionModel itemSelectionModel;
/** /**
* Construct a new WizardSelector. Load all the possible authoring kits * Construct a new WizardSelector. Load all the possible authoring kits from
* from the database and construct wizards for them. * the database and construct wizards for them.
* *
* @param model the {@link ItemSelectionModel} which will * @param model the {@link ItemSelectionModel} which will supply the wizard
* supply the wizard with its item * with its item
* *
* @param typeModel the {@link ACSObjectSelectionModel} which will * @param typeModel the {@link ACSObjectSelectionModel} which will supply
* supply the default content type * the default content type
* *
* @pre itemModel != null * @pre itemModel != null
*/ */
@ -81,16 +80,17 @@ public class WizardSelector extends AuthoringKitSelector
/** /**
* Get the wizard for the given kit. * Get the wizard for the given kit.
*
* @param kit * @param kit
* @param type * @param type
* @return * @return
*/ */
@Override
public Component instantiateKitComponent(final AuthoringKitInfo kit, public Component instantiateKitComponent(final AuthoringKitInfo kit,
final ContentTypeInfo type) { final ContentTypeInfo type) {
final ItemSelectionModel itemModel = new final ItemSelectionModel itemModel = new ItemSelectionModel(
ItemSelectionModel(type, type, (LongParameter) itemSelectionModel.getStateParameter());
(LongParameter)itemSelectionModel.getStateParameter());
final AuthoringKitWizard wizard = new AuthoringKitWizard(type, itemModel); final AuthoringKitWizard wizard = new AuthoringKitWizard(type, itemModel);
return wizard; return wizard;
@ -107,54 +107,51 @@ public class WizardSelector extends AuthoringKitSelector
private Component getCurrentWizard(PageState state) { private Component getCurrentWizard(PageState state) {
// Get the current item and extract its content type // Get the current item and extract its content type
if(!itemSelectionModel.isSelected(state)) if (!itemSelectionModel.isSelected(state)) {
throw new RuntimeException( (String) GlobalizationUtil.globalize( throw new UncheckedWrapperException("No item selected.");
"cms.ui.authoring.missing_item_id") }
.localize());
ContentItem item = final ContentItem item = (ContentItem) itemSelectionModel
(ContentItem)itemSelectionModel.getSelectedObject(state); .getSelectedObject(state);
ContentType type = item.getContentType(); final ContentType type = item.getContentType();
BigDecimal typeId; final String typeClass;
if (type == null) { if (type == null) {
// Try to get the default content type // Try to get the default content type
typeId = (BigDecimal)getComponentSelectionModel().getSelectedKey(state); typeClass = getComponentSelectionModel().getSelectedKey(state);
if(typeId == null) { if (typeClass == null || typeClass.isEmpty()) {
throw new RuntimeException((String) GlobalizationUtil.globalize( throw new UncheckedWrapperException("Content type is missing");
"cms.ui.authoring.missing_content_type")
.localize());
} }
} else { } else {
typeId = type.getID(); typeClass = type.getContentItemClass();
} }
// Return the selected wizard // Return the selected wizard
return (Component)getComponent(typeId); return (Component) getComponent(typeClass);
} }
// Choose the right wizard and run it // 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) { if (component == null) {
throw new RuntimeException( (String) GlobalizationUtil.globalize( throw new UncheckedWrapperException("No Wizard.");
"cms.ui.authoring.no_current_wizard")
.localize());
} }
c.generateXML(state, parent); component.generateXML(state, parent);
} }
/** /**
* Reset the state of the current wizard * Reset the state of the current wizard
*/ */
public void reset(PageState state) { public void reset(final PageState state) {
Resettable r = (Resettable)getCurrentWizard(state); final Resettable resettable = (Resettable) getCurrentWizard(state);
if(r != null) r.reset(state); if (resettable != null) {
resettable.reset(state);
}
} }
} }

View File

@ -24,8 +24,8 @@ import com.arsdigita.kernel.KernelConfig;
import org.libreccm.configuration.ConfigurationManager; import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.security.Shiro; import org.libreccm.security.Shiro;
import org.libreccm.security.User; import org.libreccm.security.User;
import org.libreccm.workflow.UserTask; import org.libreccm.workflow.AssignableTask;
import org.libreccm.workflow.UserTaskRepository; import org.libreccm.workflow.AssignableTaskRepository;
import org.libreccm.workflow.Workflow; import org.libreccm.workflow.Workflow;
import org.libreccm.workflow.WorkflowManager; import org.libreccm.workflow.WorkflowManager;
@ -50,7 +50,7 @@ public class AssignedTaskController {
private WorkflowManager workflowManager; private WorkflowManager workflowManager;
@Inject @Inject
private UserTaskRepository userTaskRepo; private AssignableTaskRepository userTaskRepo;
@Inject @Inject
private Shiro shiro; private Shiro shiro;
@ -71,7 +71,7 @@ public class AssignedTaskController {
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public List<RowData<Long>> getAssignedTasks(final Workflow workflow) { public List<RowData<Long>> getAssignedTasks(final Workflow workflow) {
final User user = shiro.getUser(); final User user = shiro.getUser();
final List<UserTask> tasks = userTaskRepo.getAssignedTasks(user, final List<AssignableTask> tasks = userTaskRepo.getAssignedTasks(user,
workflow); workflow);
return tasks return tasks
@ -81,7 +81,7 @@ public class AssignedTaskController {
} }
private RowData<Long> createRowData(final UserTask task) { private RowData<Long> createRowData(final AssignableTask task) {
final RowData<Long> rowData = new RowData<>(3); final RowData<Long> rowData = new RowData<>(3);

View File

@ -39,14 +39,14 @@ import org.apache.log4j.Logger;
import org.libreccm.cdi.utils.CdiUtil; import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.security.Shiro; import org.libreccm.security.Shiro;
import org.libreccm.workflow.Task; import org.libreccm.workflow.Task;
import org.libreccm.workflow.UserTask; import org.libreccm.workflow.AssignableTask;
import org.libreccm.workflow.UserTaskRepository; import org.libreccm.workflow.AssignableTaskRepository;
import org.libreccm.workflow.WorkflowConstants; import org.libreccm.workflow.WorkflowConstants;
import org.libreccm.workflow.WorkflowManager; import org.libreccm.workflow.WorkflowManager;
import org.libreccm.workflow.WorkflowRepository; import org.libreccm.workflow.WorkflowRepository;
import org.librecms.CmsConstants; import org.librecms.CmsConstants;
import org.librecms.workflow.CmsTask; import org.librecms.workflow.CmsTask;
import org.librecms.workflow.CmsTaskType; import org.librecms.workflow.CmsTaskTypeOld;
import java.util.List; import java.util.List;
@ -177,16 +177,15 @@ public final class AssignedTaskSection extends Section {
protected final Object initialValue(final PageState state) { protected final Object initialValue(final PageState state) {
final Workflow workflow = m_flow.getWorkflow(state); final Workflow workflow = m_flow.getWorkflow(state);
final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final UserTaskRepository userTaskRepo = cdiUtil.findBean( final AssignableTaskRepository userTaskRepo = cdiUtil.findBean(AssignableTaskRepository.class);
UserTaskRepository.class);
final Shiro shiro = cdiUtil.findBean(Shiro.class); final Shiro shiro = cdiUtil.findBean(Shiro.class);
return userTaskRepo.findEnabledTasksForWorkflow(shiro.getUser(), return userTaskRepo.findEnabledTasksForWorkflow(shiro.getUser(),
workflow); workflow);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final List<UserTask> getTasks(final PageState state) { final List<AssignableTask> getTasks(final PageState state) {
return (ArrayList<UserTask>) get(state); return (ArrayList<AssignableTask>) get(state);
} }
} }
@ -208,7 +207,7 @@ public final class AssignedTaskSection extends Section {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final WorkflowManager workflowManager = cdiUtil.findBean(WorkflowManager.class); 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()) { if (relevant(task) && !task.isLocked()) {
workflowManager.lockTask(task); workflowManager.lockTask(task);
} }
@ -219,7 +218,7 @@ public final class AssignedTaskSection extends Section {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final WorkflowManager workflowManager = cdiUtil.findBean(WorkflowManager.class); 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()) { if (relevant(task) && task.isLocked()) {
workflowManager.unlockTask(task); workflowManager.unlockTask(task);
} }
@ -227,7 +226,7 @@ public final class AssignedTaskSection extends Section {
} }
final boolean tasksLocked(final PageState state) { 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()) { if (relevant(task) && !task.isLocked()) {
return false; return false;
} }
@ -248,7 +247,7 @@ public final class AssignedTaskSection extends Section {
return !m_tasks.getTasks(state).isEmpty(); return !m_tasks.getTasks(state).isEmpty();
} }
private boolean relevant(final UserTask task) { private boolean relevant(final AssignableTask task) {
return true; return true;
// ToDo // ToDo

View File

@ -40,8 +40,8 @@ import org.apache.log4j.Logger;
import org.libreccm.cdi.utils.CdiUtil; import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.security.Shiro; import org.libreccm.security.Shiro;
import org.libreccm.security.User; import org.libreccm.security.User;
import org.libreccm.workflow.UserTask; import org.libreccm.workflow.AssignableTask;
import org.libreccm.workflow.UserTaskRepository; import org.libreccm.workflow.AssignableTaskRepository;
import org.libreccm.workflow.WorkflowManager; import org.libreccm.workflow.WorkflowManager;
import org.librecms.CmsConstants; import org.librecms.CmsConstants;
import org.librecms.workflow.CmsTaskTypeRepository; import org.librecms.workflow.CmsTaskTypeRepository;
@ -70,13 +70,12 @@ public final class AssignedTaskTable extends Table {
final int column = event.getColumn(); final int column = event.getColumn();
final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final UserTaskRepository userTaskRepo = cdiUtil.findBean( final AssignableTaskRepository userTaskRepo = cdiUtil.findBean(AssignableTaskRepository.class);
UserTaskRepository.class);
final WorkflowManager workflowManager = cdiUtil.findBean(WorkflowManager.class); final WorkflowManager workflowManager = cdiUtil.findBean(WorkflowManager.class);
final Shiro shiro = cdiUtil.findBean(Shiro.class); final Shiro shiro = cdiUtil.findBean(Shiro.class);
if (column == 1) { if (column == 1) {
final UserTask task = userTaskRepo.findById((Long) event final AssignableTask task = userTaskRepo.findById((Long) event
.getRowKey()); .getRowKey());
final User currentUser = shiro.getUser(); final User currentUser = shiro.getUser();
final User lockingUser = task.getLockingUser(); final User lockingUser = task.getLockingUser();

View File

@ -27,7 +27,7 @@ import com.arsdigita.bebop.parameters.IntegerParameter;
import com.arsdigita.cms.ui.BaseForm; import com.arsdigita.cms.ui.BaseForm;
import com.arsdigita.cms.ui.ListOptionPrintListener; import com.arsdigita.cms.ui.ListOptionPrintListener;
import org.librecms.workflow.CmsTaskType; import org.librecms.workflow.CmsTaskTypeOld;
import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.kernel.KernelConfig; import com.arsdigita.kernel.KernelConfig;
@ -142,27 +142,27 @@ class BaseTaskForm extends BaseForm {
} }
*/ */
// Fix this one too // Fix this one too
private class TaskTypePrintListener extends ListOptionPrintListener<CmsTaskType> { private class TaskTypePrintListener extends ListOptionPrintListener<CmsTaskTypeOld> {
@Override @Override
protected List<CmsTaskType> getDataQuery(final PageState state) { protected List<CmsTaskTypeOld> getDataQuery(final PageState state) {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final CmsTaskTypeRepository taskTypeRepo = cdiUtil.findBean( final CmsTaskTypeRepository taskTypeRepo = cdiUtil.findBean(
CmsTaskTypeRepository.class); CmsTaskTypeRepository.class);
final List<CmsTaskType> taskTypes = taskTypeRepo.findAll(); final List<CmsTaskTypeOld> taskTypes = taskTypeRepo.findAll();
return taskTypes; return taskTypes;
} }
@Override @Override
public String getKey(final CmsTaskType taskType) { public String getKey(final CmsTaskTypeOld taskType) {
return Long.toString(taskType.getTaskTypeId()); return Long.toString(taskType.getTaskTypeId());
} }
@Override @Override
public String getValue(final CmsTaskType taskType) { public String getValue(final CmsTaskTypeOld taskType) {
final KernelConfig kernelConfig = KernelConfig.getConfig(); final KernelConfig kernelConfig = KernelConfig.getConfig();
final Locale defaultLocale = kernelConfig.getDefaultLocale(); final Locale defaultLocale = kernelConfig.getDefaultLocale();
return taskType.getName().getValue(defaultLocale); return taskType.getName().getValue(defaultLocale);

View File

@ -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 <a href="mailto:jens.pelzetter">Jens Pelzetter</a>
*/
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);
}
}
}

View File

@ -30,7 +30,7 @@ import com.arsdigita.bebop.form.OptionGroup;
import com.arsdigita.kernel.KernelConfig; import com.arsdigita.kernel.KernelConfig;
import org.librecms.workflow.CmsTask; import org.librecms.workflow.CmsTask;
import org.librecms.workflow.CmsTaskType; import org.librecms.workflow.CmsTaskTypeOld;
import com.arsdigita.util.UncheckedWrapperException; import com.arsdigita.util.UncheckedWrapperException;
@ -120,7 +120,7 @@ class TaskAddForm extends BaseTaskForm {
defaultLocale, defaultLocale,
((String) m_description.getValue(state))); ((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.setTaskType(taskType);
task.setActive(true); task.setActive(true);

View File

@ -30,7 +30,7 @@ import com.arsdigita.cms.ui.UserSearchForm;
import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.globalization.GlobalizedMessage;
import org.libreccm.security.User; import org.libreccm.security.User;
import org.libreccm.workflow.UserTask; import org.libreccm.workflow.AssignableTask;
import com.arsdigita.xml.Element; import com.arsdigita.xml.Element;
@ -146,7 +146,7 @@ class TaskAddUser extends SimpleContainer {
WorkflowManager.class); WorkflowManager.class);
final UserRepository userRepo = cdiUtil.findBean(UserRepository.class); final UserRepository userRepo = cdiUtil.findBean(UserRepository.class);
final UserTask task = m_task.getTask(state); final AssignableTask task = m_task.getTask(state);
User user; User user;
for (int i = 0; i < users.length; i++) { for (int i = 0; i < users.length; i++) {

View File

@ -37,7 +37,7 @@ import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.configuration.ConfigurationManager; import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.workflow.Task; import org.libreccm.workflow.Task;
import org.libreccm.workflow.TaskRepository; import org.libreccm.workflow.TaskRepository;
import org.librecms.workflow.CmsTaskType; import org.librecms.workflow.CmsTaskTypeOld;
import org.librecms.workflow.CmsTaskTypeRepository; import org.librecms.workflow.CmsTaskTypeRepository;
import java.util.ArrayList; import java.util.ArrayList;
@ -144,7 +144,7 @@ class TaskEditForm extends BaseTaskForm {
defaultLocale, defaultLocale,
(String) m_description.getValue(state)); (String) m_description.getValue(state));
final CmsTaskType taskType = taskTypeRepo.findById((Long) m_type final CmsTaskTypeOld taskType = taskTypeRepo.findById((Long) m_type
.getValue(state)); .getValue(state));
task.setTaskType(taskType); task.setTaskType(taskType);

View File

@ -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;
/**
* <p>
* A form that prompts the user to comment on and approve tasks and then
* finishes the task if it was approved.</p>
*
* @author Justin Ross &lt;jross@redhat.com&gt;
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
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<ContentItem> 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<Task> 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);
}
}

View File

@ -49,7 +49,7 @@ import org.libreccm.security.Role;
import org.libreccm.security.RoleRepository; import org.libreccm.security.RoleRepository;
import org.libreccm.security.Shiro; import org.libreccm.security.Shiro;
import org.libreccm.workflow.Task; import org.libreccm.workflow.Task;
import org.libreccm.workflow.UserTask; import org.libreccm.workflow.AssignableTask;
import org.libreccm.workflow.WorkflowManager; import org.libreccm.workflow.WorkflowManager;
import org.librecms.CmsConstants; import org.librecms.CmsConstants;
import org.librecms.contentsection.privileges.AdminPrivileges; import org.librecms.contentsection.privileges.AdminPrivileges;
@ -173,7 +173,7 @@ final class TaskItemPane extends BaseItemPane {
final User user = shiro.getUser(); final User user = shiro.getUser();
final List<UserTask> tasks = workflowManager.lockedBy(user); final List<AssignableTask> tasks = workflowManager.lockedBy(user);
return tasks.contains(task); return tasks.contains(task);
} }

View File

@ -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 <a href="mail:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
* */
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);
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*
*/
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");
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*
*/
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");
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
* */
public interface TaskURLGenerator {
String generateURL(long item_id, long task_id);
}

View File

@ -73,21 +73,24 @@ import static org.librecms.CmsConstants.*;
query = "SELECT i FROM ContentItem i " query = "SELECT i FROM ContentItem i "
+ "JOIN i.categories c " + "JOIN i.categories c "
+ "WHERE c.category = :folder " + "WHERE c.category = :folder "
+ "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + "'") + "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER
+ "'")
, ,
@NamedQuery( @NamedQuery(
name = "ContentItem.countItemsInFolder", name = "ContentItem.countItemsInFolder",
query = "SELECT count(i) FROM ContentItem i " query = "SELECT count(i) FROM ContentItem i "
+ "JOIN i.categories c " + "JOIN i.categories c "
+ "WHERE c.category = :folder " + "WHERE c.category = :folder "
+ "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + "'") + "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER
+ "'")
, ,
@NamedQuery( @NamedQuery(
name = "ContentItem.countByNameInFolder", name = "ContentItem.countByNameInFolder",
query = "SELECT COUNT(i) FROM ContentItem i " query = "SELECT COUNT(i) FROM ContentItem i "
+ "JOIN i.categories c " + "JOIN i.categories c "
+ "WHERE c.category = :folder " + "WHERE c.category = :folder "
+ "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + "' " + "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER
+ "' "
+ "AND i.displayName = :name") + "AND i.displayName = :name")
, ,
@NamedQuery( @NamedQuery(
@ -95,7 +98,8 @@ import static org.librecms.CmsConstants.*;
query = "SELECT i FROM ContentItem i " query = "SELECT i FROM ContentItem i "
+ "JOIN i.categories c " + "JOIN i.categories c "
+ "WHERE c.category = :folder " + "WHERE c.category = :folder "
+ "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + "' " + "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER
+ "' "
+ "AND LOWER(i.displayName) LIKE CONCAT(LOWER(:name), '%')") + "AND LOWER(i.displayName) LIKE CONCAT(LOWER(:name), '%')")
, ,
@NamedQuery( @NamedQuery(
@ -103,7 +107,8 @@ import static org.librecms.CmsConstants.*;
query = "SELECT COUNT(i) FROM ContentItem i " query = "SELECT COUNT(i) FROM ContentItem i "
+ "JOIN i.categories c " + "JOIN i.categories c "
+ "WHERE c.category = :folder " + "WHERE c.category = :folder "
+ "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER + "' " + "AND c.type = '" + CATEGORIZATION_TYPE_FOLDER
+ "' "
+ "AND LOWER(i.displayName) LIKE CONCAT(LOWER(:name), '%')" + "AND LOWER(i.displayName) LIKE CONCAT(LOWER(:name), '%')"
) )
, ,
@ -125,7 +130,12 @@ import static org.librecms.CmsConstants.*;
query = "SELECT i FROM ContentItem i " query = "SELECT i FROM ContentItem i "
+ "WHERE i.itemUuid = :uuid " + "WHERE i.itemUuid = :uuid "
+ "AND i.version = org.librecms.contentsection.ContentItemVersion.LIVE") + "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, public class ContentItem extends CcmObject implements Serializable,
InheritsPermissions { InheritsPermissions {

View File

@ -169,7 +169,8 @@ public class ContentItemManager {
* *
* @param <T> The type of the content item. * @param <T> The type of the content item.
* @param name The name (URL stub) of the new 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 section The content section in which the item is
* generated.
* @param folder The folder in which in the item is stored. * @param folder The folder in which in the item is stored.
* @param workflowTemplate The template for the workflow to apply to the new * @param workflowTemplate The template for the workflow to apply to the new
* item. * item.
@ -225,7 +226,7 @@ public class ContentItemManager {
if (workflowTemplate != null) { if (workflowTemplate != null) {
final Workflow workflow = workflowManager.createWorkflow( final Workflow workflow = workflowManager.createWorkflow(
workflowTemplate); workflowTemplate, item);
item.setWorkflow(workflow); item.setWorkflow(workflow);
} }
@ -319,8 +320,9 @@ public class ContentItemManager {
* *
* @param item The item to copy. * @param item The item to copy.
* @param targetFolder The folder in which the copy is created. If the * @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 * target folder is the same folder as the folder of the
* index is appended to the name of the item. * original item an index is appended to the name of the
* item.
* *
* @return The copy of the item * @return The copy of the item
*/ */
@ -383,7 +385,7 @@ public class ContentItemManager {
final WorkflowTemplate template = draftItem.getWorkflow() final WorkflowTemplate template = draftItem.getWorkflow()
.getTemplate(); .getTemplate();
final Workflow copyWorkflow = workflowManager.createWorkflow( final Workflow copyWorkflow = workflowManager.createWorkflow(
template); template, item);
copy.setWorkflow(copyWorkflow); copy.setWorkflow(copyWorkflow);
} }
@ -562,7 +564,8 @@ public class ContentItemManager {
private void copyAttachmentList(final AttachmentList sourceList, private void copyAttachmentList(final AttachmentList sourceList,
final ContentItem target) { final ContentItem target) {
final AttachmentList targetList = new AttachmentList(); final AttachmentList targetList = new AttachmentList();
copyLocalizedString(sourceList.getDescription(), targetList.getDescription()); copyLocalizedString(sourceList.getDescription(), targetList
.getDescription());
targetList.setItem(target); targetList.setItem(target);
targetList.setName(sourceList.getName()); targetList.setName(sourceList.getName());
targetList.setOrder(sourceList.getOrder()); targetList.setOrder(sourceList.getOrder());
@ -844,8 +847,8 @@ public class ContentItemManager {
targetAsset = sourceAttachment.getAsset(); targetAsset = sourceAttachment.getAsset();
} else { } else {
try { try {
targetAsset = sourceAttachment.getAsset().getClass(). targetAsset = sourceAttachment.getAsset().getClass()
newInstance(); .newInstance();
} catch (InstantiationException | IllegalAccessException ex) { } catch (InstantiationException | IllegalAccessException ex) {
throw new UncheckedWrapperException(ex); throw new UncheckedWrapperException(ex);
} }
@ -1143,9 +1146,9 @@ public class ContentItemManager {
* @param type Type of the content item. * @param type Type of the content item.
* *
* @return The live version of an item. If the item provided is already the * @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 * live version the provided item is returned, otherwise the live
* returned. If there is no live version an empty {@link Optional} is * version is returned. If there is no live version an empty
* returned. * {@link Optional} is returned.
*/ */
@AuthorizationRequired @AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
@ -1203,10 +1206,10 @@ public class ContentItemManager {
* @param type Type of the item. * @param type Type of the item.
* *
* @return The draft version of the provided content item. If the provided * @return The draft version of the provided content item. If the provided
* item is the draft version the provided item is simply returned. Otherwise * item is the draft version the provided item is simply returned.
* the draft version is retrieved from the database and is returned. Each * Otherwise the draft version is retrieved from the database and is
* content item has a draft version (otherwise something is seriously wrong * returned. Each content item has a draft version (otherwise
* with the database) this method will * something is seriously wrong with the database) this method will
* <b>never</b> return {@code null}. * <b>never</b> return {@code null}.
*/ */
@AuthorizationRequired @AuthorizationRequired

View File

@ -29,7 +29,9 @@ import java.util.UUID;
import javax.enterprise.context.RequestScoped; import javax.enterprise.context.RequestScoped;
import javax.inject.Inject; import javax.inject.Inject;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery; import javax.persistence.TypedQuery;
import org.libreccm.workflow.Workflow;
/** /**
* Repository for content items. * Repository for content items.
@ -251,4 +253,17 @@ public class ContentItemRepository
return query.getSingleResult(); return query.getSingleResult();
} }
public Optional<ContentItem> findItemWithWorkflow(final Workflow workflow) {
final TypedQuery<ContentItem> query = getEntityManager()
.createNamedQuery("ContentItem.findItemWithWorkflow",
ContentItem.class);
query.setParameter("workflow", workflow);
try {
return Optional.of(query.getSingleResult());
} catch(NoResultException ex) {
return Optional.empty();
}
}
} }

View File

@ -18,14 +18,15 @@
*/ */
package org.librecms.workflow; package org.librecms.workflow;
import org.libreccm.workflow.UserTask; import org.libreccm.workflow.AssignableTask;
import java.io.Serializable; import java.io.Serializable;
import java.util.Objects; import java.util.Objects;
import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.JoinColumn; import javax.persistence.EnumType;
import javax.persistence.OneToOne; import javax.persistence.Enumerated;
import javax.persistence.Table; import javax.persistence.Table;
import static org.librecms.CmsConstants.*; import static org.librecms.CmsConstants.*;
@ -36,12 +37,12 @@ import static org.librecms.CmsConstants.*;
*/ */
@Entity @Entity
@Table(name = "WORKFLOW_TASKS", schema = DB_SCHEMA) @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; private static final long serialVersionUID = -3988352366529930659L;
@OneToOne @Column(name = "TASK_TYPE")
@JoinColumn(name = "TASK_TYPE_ID") @Enumerated(EnumType.STRING)
private CmsTaskType taskType; private CmsTaskType taskType;
public CmsTaskType getTaskType() { public CmsTaskType getTaskType() {
@ -79,7 +80,7 @@ public class CmsTask extends UserTask implements Serializable {
return false; return false;
} }
return Objects.equals(taskType, other.taskType); return Objects.equals(taskType, other.getTaskType());
} }
@Override @Override

View File

@ -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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -18,188 +18,38 @@
*/ */
package org.librecms.workflow; 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 org.librecms.contentsection.privileges.ItemPrivileges;
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.*;
/** /**
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@Entity public enum CmsTaskType {
@Table(name = "WORKFLOW_TASK_TYPES", schema = DB_SCHEMA)
public class CmsTaskType implements Serializable {
private static final long serialVersionUID = -4326031746212785970L; AUTHOR(AuthoringTaskURLGenerator.class, ItemPrivileges.EDIT),
EDIT(EditingTaskURLGenerator.class, ItemPrivileges.APPROVE),
DEPLOY(DeployTaskURLGenerator.class, ItemPrivileges.PUBLISH);
@Id private final Class<? extends TaskURLGenerator> urlGenerator;
@GeneratedValue(strategy = GenerationType.AUTO) private final String privilege;
@Column(name = "TASK_TYPE_ID")
private long taskTypeId;
@Embedded private CmsTaskType(final Class<? extends TaskURLGenerator> urlGenerator,
@AssociationOverride( final String privilege) {
name = "values", this.urlGenerator = urlGenerator;
joinTable = @JoinTable(name = "ARTICLE_LEADS", this.privilege = privilege;
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<TaskEventUrlGenerator> generators;
public CmsTaskType() {
generators = new HashSet<>();
} }
public long getTaskTypeId() { public Class<? extends TaskURLGenerator> getUrlGenerator() {
return taskTypeId; return urlGenerator;
}
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() { public String getPrivilege() {
return privilege; return privilege;
} }
public void setPrivilege(final String privilege) {
this.privilege = privilege;
}
public Set<TaskEventUrlGenerator> getGenerators() {
if (generators == null) {
return null;
} else {
return Collections.unmodifiableSet(generators);
}
}
protected void setGenerators(final Set<TaskEventUrlGenerator> generators) {
this.generators = generators;
}
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);
}
} }

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class CmsTaskTypeRepository extends AbstractEntityRepository<Long, CmsTaskType>{
@Override
public Class<CmsTaskType> getEntityClass() {
return CmsTaskType.class;
}
@Override
public boolean isNew(final CmsTaskType taskType) {
return taskType.getTaskTypeId() == 0;
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@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);
}
}

View File

@ -45,31 +45,37 @@ import javax.persistence.TemporalType;
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@Entity @Entity
@Table(name = "WORKFLOW_USER_TASKS", schema = DB_SCHEMA) @Table(name = "WORKFLOW_ASSIGNABLE_TASKS", schema = DB_SCHEMA)
@NamedQueries({ @NamedQueries({
@NamedQuery( @NamedQuery(
name = "UserTask.findLockedBy", name = "AssignableTask.findLockedBy",
query = "SELECT t FROM UserTask t WHERE t.lockingUser = :user") query = "SELECT t FROM AssignableTask t WHERE t.lockingUser = :user")
, ,
@NamedQuery( @NamedQuery(
name = "UserTask.findEnabledTasksForWorkflow", name = "AssignableTask.findEnabledTasksForWorkflow",
query = "SELECT t FROM UserTask t " query = "SELECT t FROM AssignableTask t "
+ "WHERE t.lockingUser = :user " + "WHERE t.lockingUser = :user "
+ "AND t.workflow = :workflow" + "AND t.workflow = :workflow"
) )
, ,
@NamedQuery( @NamedQuery(
name = "UserTask.findAssignedTasks", name = "AssignableTask.findAssignedTasks",
query = "SELECT t FROM UserTask t " query = "SELECT t FROM AssignableTask t "
+ "WHERE t.assignments.role IN :roles " + "WHERE t.assignments.role IN :roles "
+ "AND t.assignments.workflow = :workflow " + "AND t.assignments.workflow = :workflow "
+ "AND t.active = true") + "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 //Can't reduce complexity yet
@SuppressWarnings({"PMD.CyclomaticComplexity", @SuppressWarnings({"PMD.CyclomaticComplexity",
"PMD.StdCyclomaticComplexity", "PMD.StdCyclomaticComplexity",
"PMD.ModifiedCyclomaticComplexity"}) "PMD.ModifiedCyclomaticComplexity"})
public class UserTask extends Task implements Serializable { public class AssignableTask extends Task implements Serializable {
private static final long serialVersionUID = 4188064584389893019L; private static final long serialVersionUID = 4188064584389893019L;
@ -99,7 +105,7 @@ public class UserTask extends Task implements Serializable {
@OneToMany(mappedBy = "task") @OneToMany(mappedBy = "task")
private List<TaskAssignment> assignments; private List<TaskAssignment> assignments;
public UserTask() { public AssignableTask() {
super(); super();
assignments = new ArrayList<>(); assignments = new ArrayList<>();
} }
@ -217,10 +223,10 @@ public class UserTask extends Task implements Serializable {
return false; return false;
} }
if (!(obj instanceof UserTask)) { if (!(obj instanceof AssignableTask)) {
return false; return false;
} }
final UserTask other = (UserTask) obj; final AssignableTask other = (AssignableTask) obj;
if (!other.canEqual(this)) { if (!other.canEqual(this)) {
return false; return false;
} }
@ -245,7 +251,7 @@ public class UserTask extends Task implements Serializable {
@Override @Override
public boolean canEqual(final Object obj) { public boolean canEqual(final Object obj) {
return obj instanceof UserTask; return obj instanceof AssignableTask;
} }
@Override @Override

View File

@ -33,32 +33,35 @@ import javax.persistence.TypedQuery;
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@RequestScoped @RequestScoped
public class UserTaskRepository extends AbstractEntityRepository<Long, UserTask> { public class AssignableTaskRepository
extends AbstractEntityRepository<Long, AssignableTask> {
@Override @Override
public Class<UserTask> getEntityClass() { public Class<AssignableTask> getEntityClass() {
return UserTask.class; return AssignableTask.class;
} }
@Override @Override
public boolean isNew(final UserTask task) { public boolean isNew(final AssignableTask task) {
return task.getTaskId() == 0; return task.getTaskId() == 0;
} }
public List<UserTask> findEnabledTasksForWorkflow(final User user, public List<AssignableTask> findEnabledTasksForWorkflow(
final Workflow workflow) { final User user, final Workflow workflow) {
final TypedQuery<UserTask> query = getEntityManager().createNamedQuery( final TypedQuery<AssignableTask> query = getEntityManager()
"UserTask.findEnabledTasksForWorkflow", UserTask.class); .createNamedQuery(
"UserTask.findEnabledTasksForWorkflow", AssignableTask.class);
query.setParameter("user", user); query.setParameter("user", user);
query.setParameter("workflow", workflow); query.setParameter("workflow", workflow);
return query.getResultList(); return query.getResultList();
} }
public List<UserTask> getAssignedTasks(final User user, public List<AssignableTask> getAssignedTasks(final User user,
final Workflow workflow) { final Workflow workflow) {
final TypedQuery<UserTask> query = getEntityManager().createNamedQuery( final TypedQuery<AssignableTask> query = getEntityManager()
"UserTask.findAssignedTasks", UserTask.class); .createNamedQuery(
"UserTask.findAssignedTasks", AssignableTask.class);
final List<Role> roles = user.getRoleMemberships() final List<Role> roles = user.getRoleMemberships()
.stream() .stream()
.map(membership -> membership.getRole()) .map(membership -> membership.getRole())

View File

@ -30,9 +30,10 @@ import java.util.Objects;
import javax.persistence.AssociationOverride; import javax.persistence.AssociationOverride;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Embedded; import javax.persistence.Embedded;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType; import javax.persistence.GenerationType;
import javax.persistence.Id; import javax.persistence.Id;
@ -40,9 +41,11 @@ import javax.persistence.Inheritance;
import javax.persistence.InheritanceType; import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.JoinTable; import javax.persistence.JoinTable;
import javax.persistence.Lob;
import javax.persistence.ManyToMany; import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table; import javax.persistence.Table;
/** /**
@ -59,6 +62,35 @@ import javax.persistence.Table;
"PMD.ShortClassName", "PMD.ShortClassName",
"PMD.TooManyMethods", "PMD.TooManyMethods",
"PMD.AvoidDuplicateLiterals"}) "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 { public class Task implements Serializable {
private static final long serialVersionUID = 8161343036908150426L; private static final long serialVersionUID = 8161343036908150426L;
@ -90,7 +122,8 @@ public class Task implements Serializable {
private boolean active; private boolean active;
@Column(name = "TASK_STATE", length = 512) @Column(name = "TASK_STATE", length = 512)
private String taskState; @Enumerated(EnumType.STRING)
private TaskState taskState;
@ManyToOne @ManyToOne
@JoinColumn(name = "WORKFLOW_ID") @JoinColumn(name = "WORKFLOW_ID")
@ -108,14 +141,9 @@ public class Task implements Serializable {
@JoinColumn(name = "DEPENDENT_TASK_ID")}) @JoinColumn(name = "DEPENDENT_TASK_ID")})
private List<Task> dependsOn; private List<Task> dependsOn;
@ElementCollection @OneToMany
@JoinTable(name = "WORKFLOW_TASK_COMMENTS", @JoinColumn(name = "TASK_ID")
schema = DB_SCHEMA, private List<TaskComment> comments;
joinColumns = {
@JoinColumn(name = "TASK_ID")})
@Column(name = "COMMENT")
@Lob
private List<String> comments;
public Task() { public Task() {
super(); super();
@ -159,11 +187,11 @@ public class Task implements Serializable {
this.active = active; this.active = active;
} }
public String getTaskState() { public TaskState getTaskState() {
return taskState; return taskState;
} }
public void setTaskState(final String taskState) { protected void setTaskState(final TaskState taskState) {
this.taskState = taskState; this.taskState = taskState;
} }
@ -215,7 +243,7 @@ public class Task implements Serializable {
dependsOn.remove(task); dependsOn.remove(task);
} }
public List<String> getComments() { public List<TaskComment> getComments() {
if (comments == null) { if (comments == null) {
return null; return null;
} else { } else {
@ -223,15 +251,15 @@ public class Task implements Serializable {
} }
} }
protected void setComments(final List<String> comments) { protected void setComments(final List<TaskComment> comments) {
this.comments = comments; this.comments = comments;
} }
public void addComment(final String comment) { public void addComment(final TaskComment comment) {
comments.add(comment); comments.add(comment);
} }
public void removeComment(final String comment) { public void removeComment(final TaskComment comment) {
comments.remove(comment); comments.remove(comment);
} }

View File

@ -51,7 +51,7 @@ public class TaskAssignment implements Serializable {
@ManyToOne @ManyToOne
@JoinColumn(name = "TASK_ID") @JoinColumn(name = "TASK_ID")
private UserTask task; private AssignableTask task;
@ManyToOne @ManyToOne
@JoinColumn(name = "ROLE_ID") @JoinColumn(name = "ROLE_ID")
@ -65,11 +65,11 @@ public class TaskAssignment implements Serializable {
this.taskAssignmentId = taskAssignmentId; this.taskAssignmentId = taskAssignmentId;
} }
public UserTask getTask() { public AssignableTask getTask() {
return task; return task;
} }
protected void setTask(final UserTask task) { protected void setTask(final AssignableTask task) {
this.task = task; this.task = task;
} }

View File

@ -20,6 +20,7 @@ package org.libreccm.workflow;
import static org.libreccm.core.CoreConstants.*; import static org.libreccm.core.CoreConstants.*;
import org.libreccm.core.CcmObject;
import org.libreccm.l10n.LocalizedString; import org.libreccm.l10n.LocalizedString;
import java.io.Serializable; import java.io.Serializable;
@ -32,6 +33,8 @@ import javax.persistence.AssociationOverride;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Embedded; import javax.persistence.Embedded;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType; import javax.persistence.GenerationType;
import javax.persistence.Id; import javax.persistence.Id;
@ -40,7 +43,10 @@ import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.JoinTable; import javax.persistence.JoinTable;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table; import javax.persistence.Table;
/** /**
@ -50,6 +56,12 @@ import javax.persistence.Table;
@Entity @Entity
@Table(name = "WORKFLOWS", schema = DB_SCHEMA) @Table(name = "WORKFLOWS", schema = DB_SCHEMA)
@Inheritance(strategy = InheritanceType.JOINED) @Inheritance(strategy = InheritanceType.JOINED)
@NamedQueries({
@NamedQuery(
name = "Workflow.findForObject",
query = "SELECT w FROM Workflow w "
+ "WHERE W.object = :object")
})
public class Workflow implements Serializable { public class Workflow implements Serializable {
private static final long serialVersionUID = 4322500264543325829L; private static final long serialVersionUID = 4322500264543325829L;
@ -82,6 +94,21 @@ public class Workflow implements Serializable {
})) }))
private LocalizedString description; 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") @OneToMany(mappedBy = "workflow")
private List<Task> tasks; private List<Task> tasks;
@ -125,6 +152,38 @@ public class Workflow implements Serializable {
this.description = description; 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<Task> getTasks() { public List<Task> getTasks() {
if (tasks == null) { if (tasks == null) {
return null; return null;
@ -150,6 +209,11 @@ public class Workflow implements Serializable {
int hash = 5; int hash = 5;
hash = 79 * hash + (int) (this.workflowId ^ (this.workflowId >>> 32)); hash = 79 * hash + (int) (this.workflowId ^ (this.workflowId >>> 32));
hash = 79 * hash + Objects.hashCode(this.name); 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; return hash;
} }
@ -166,10 +230,31 @@ public class Workflow implements Serializable {
return false; return false;
} }
if (this.workflowId != other.getWorkflowId()) { if (workflowId != other.getWorkflowId()) {
return false; return false;
} }
return Objects.equals(this.name, other.getName());
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;
}
if (!Objects.equals(tasksState, other.getTasksState())) {
return false;
}
return Objects.equals(object, other.getObject());
} }
@ -185,11 +270,19 @@ public class Workflow implements Serializable {
public String toString(final String data) { public String toString(final String data) {
return String.format("%s{ " return String.format("%s{ "
+ "workflowId = %d, " + "workflowId = %d, "
+ "name = \"%s\"%s" + "name = \"%s\", "
+ "description = \"%s\", "
+ "state = \"%s\", "
+ "active = %b"
+ "object = \"%s\"%s"
+ " }", + " }",
super.toString(), super.toString(),
workflowId, workflowId,
name, Objects.toString(name),
Objects.toString(description),
Objects.toString(state),
active,
Objects.toString(object),
data); data);
} }

View File

@ -18,14 +18,17 @@
*/ */
package org.libreccm.workflow; 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.core.CoreConstants;
import org.libreccm.l10n.LocalizedString; import org.libreccm.l10n.LocalizedString;
import org.libreccm.security.AuthorizationRequired; import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.RequiresPrivilege; import org.libreccm.security.RequiresPrivilege;
import org.libreccm.security.Role;
import org.libreccm.security.RoleRepository;
import org.libreccm.security.Shiro; import org.libreccm.security.Shiro;
import org.libreccm.security.User;
import java.beans.BeanInfo; import java.beans.BeanInfo;
import java.beans.IntrospectionException; import java.beans.IntrospectionException;
@ -33,12 +36,14 @@ import java.beans.Introspector;
import java.beans.PropertyDescriptor; import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped; import javax.enterprise.context.RequestScoped;
import javax.inject.Inject; import javax.inject.Inject;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
@ -52,6 +57,9 @@ import javax.transaction.Transactional;
@RequestScoped @RequestScoped
public class WorkflowManager { public class WorkflowManager {
private final static Logger LOGGER = LogManager.getLogger(
WorkflowManager.class);
@Inject @Inject
private EntityManager entityManager; private EntityManager entityManager;
@ -62,15 +70,28 @@ public class WorkflowManager {
private TaskRepository taskRepo; private TaskRepository taskRepo;
@Inject @Inject
private RoleRepository roleRepo; private TaskManager taskManager;
@Inject @Inject
private Shiro shiro; 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 @AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED) @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 Workflow workflow = new Workflow();
final LocalizedString name = new LocalizedString(); final LocalizedString name = new LocalizedString();
@ -90,6 +111,9 @@ public class WorkflowManager {
template.getTasks().forEach(taskTemplate -> fixTaskDependencies( template.getTasks().forEach(taskTemplate -> fixTaskDependencies(
taskTemplate, tasks.get(taskTemplate.getTaskId()), tasks)); taskTemplate, tasks.get(taskTemplate.getTaskId()), tasks));
workflow.setObject(object);
workflow.setState(WorkflowState.INIT);
tasks.values().forEach(task -> taskRepo.save(task)); tasks.values().forEach(task -> taskRepo.save(task));
workflowRepo.save(workflow); workflowRepo.save(workflow);
@ -172,139 +196,161 @@ public class WorkflowManager {
@AuthorizationRequired @AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public void addTask(final Workflow workflow, final Task task) { public List<Task> findEnabledTasks(final Workflow workflow) {
workflow.addTask(task); if (workflow.getState() == WorkflowState.DELETED
task.setWorkflow(workflow); || workflow.getState() == WorkflowState.STOPPED) {
LOGGER.debug(String.format("Workflow state is \"%s\". Workflow "
+ "has no enabled tasks.",
workflow.getState().toString()));
return Collections.emptyList();
}
workflowRepo.save(workflow); final TypedQuery<Task> query = entityManager.createNamedQuery(
taskRepo.save(task); "Task.findEnabledTasks", Task.class);
query.setParameter("workflow", workflow);
return Collections.unmodifiableList(query.getResultList());
} }
@AuthorizationRequired @AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public void removeTask(final Workflow workflow, final Task task) { public List<Task> findFinishedTasks(final Workflow workflow) {
workflow.removeTask(task); final TypedQuery<Task> query = entityManager.createNamedQuery(
task.setWorkflow(null); "Task.findFinishedTasks", Task.class);
query.setParameter("workflow", workflow);
workflowRepo.save(workflow); return Collections.unmodifiableList(query.getResultList());
taskRepo.save(task);
} }
@AuthorizationRequired @AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public void assignTask(final UserTask task, final Role role) { public List<AssignableTask> findOverdueTasks(final Workflow workflow) {
final TaskAssignment assignment = new TaskAssignment(); final TypedQuery<AssignableTask> query = entityManager.createNamedQuery(
assignment.setTask(task); "AssignableTask.findOverdueTasks", AssignableTask.class);
assignment.setRole(role); query.setParameter("workflow", workflow);
query.setParameter("now", new Date());
task.addAssignment(assignment); return Collections.unmodifiableList(query.getResultList());
role.addAssignedTask(assignment);
entityManager.persist(assignment);
taskRepo.save(task);
roleRepo.save(role);
} }
@AuthorizationRequired @AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public void retractTask(final UserTask task, final Role role) {
final List<TaskAssignment> 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);
}
}
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
public void addDependentTask(final Task parent, final Task task) {
parent.addDependentTask(task);
task.addDependsOn(parent);
taskRepo.save(task);
taskRepo.save(parent);
}
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
public void removeDependentTask(final Task parent, final Task task) {
parent.removeDependentTask(task);
task.removeDependsOn(parent);
taskRepo.save(task);
taskRepo.save(parent);
}
@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<UserTask> lockedBy(final User user) {
final TypedQuery<UserTask> query = entityManager.createNamedQuery(
"UserTask.findLockedBy", UserTask.class);
query.setParameter("user", user);
return query.getResultList();
}
public void start(final Workflow workflow) { public void start(final Workflow workflow) {
if (workflow.getTasks() != null && !workflow.getTasks().isEmpty()) { final WorkflowState oldState = workflow.getState();
final Task first = workflow.getTasks().get(0);
if (first instanceof UserTask) { workflow.setState(WorkflowState.STARTED);
final User user = shiro.getUser(); if (oldState == WorkflowState.INIT) {
lockTask((UserTask) first); workflow.setActive(true);
updateState(workflow);
for (final Task current : workflow.getTasks()) {
current.setActive(true);
taskManager.updateState(current);
} }
} }
workflowRepo.save(workflow);
} }
/** @AuthorizationRequired
* Gets the state of a workflow. @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
* @Transactional(Transactional.TxType.REQUIRED)
* @param workflow private void updateState(final Workflow workflow) {
* @return if (workflow.getTasksState() == TaskState.ENABLED) {
*/ final TypedQuery<Long> query = entityManager.createNamedQuery(
public int getState(final Workflow workflow) { "Task.countUnfinishedAndActiveTasksForWorkflow", Long.class);
query.setParameter("workflow", workflow);
final Optional<Task> activeTask = workflow.getTasks() final Long result = query.getSingleResult();
.stream()
.filter(task -> task.isActive())
.findAny();
if (activeTask.isPresent()) { if (result > 0) {
return WorkflowConstants.STARTED; return;
} else { } else {
return -1; finish(workflow);
} }
} }
if (workflow.getTasksState() == TaskState.FINISHED) {
final TypedQuery<Long> query = entityManager.createNamedQuery(
"Task.countUnfinishedTasksForWorkflow", Long.class);
query.setParameter("workflow", workflow);
final Long result = query.getSingleResult();
if (result > 0) {
enable(workflow);
}
}
}
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
public void stop(final Workflow workflow) {
workflow.setState(WorkflowState.STOPPED);
workflowRepo.save(workflow);
}
@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)));
}
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);
}
} }

View File

@ -19,8 +19,13 @@
package org.libreccm.workflow; package org.libreccm.workflow;
import org.libreccm.core.AbstractEntityRepository; import org.libreccm.core.AbstractEntityRepository;
import org.libreccm.core.CcmObject;
import java.util.Optional;
import javax.enterprise.context.RequestScoped; import javax.enterprise.context.RequestScoped;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;
/** /**
* *
@ -39,4 +44,21 @@ public class WorkflowRepository extends AbstractEntityRepository<Long, Workflow>
return workflow.getWorkflowId() == 0; return workflow.getWorkflowId() == 0;
} }
public Optional<Workflow> findWorkflowForObject(final CcmObject object) {
if (object == null) {
throw new IllegalArgumentException(
"Can't find a workflow for object null.");
}
final TypedQuery<Workflow> query = getEntityManager().createNamedQuery(
"Workflow.findForObject", Workflow.class);
query.setParameter("object", object);
try {
return Optional.of(query.getSingleResult());
} catch(NoResultException ex) {
return Optional.empty();
}
}
} }

View File

@ -20,6 +20,8 @@ package org.libreccm.workflow;
import static org.libreccm.core.CoreConstants.*; import static org.libreccm.core.CoreConstants.*;
import org.libreccm.core.CcmObject;
import java.io.Serializable; import java.io.Serializable;
import javax.persistence.Entity; import javax.persistence.Entity;
@ -35,6 +37,12 @@ public class WorkflowTemplate extends Workflow implements Serializable {
private static final long serialVersionUID = 5770519379144947171L; private static final long serialVersionUID = 5770519379144947171L;
@Override
protected void setObject(final CcmObject object) {
throw new UnsupportedOperationException(
"A WorkflowTemplate has no object.");
}
@Override @Override
public int hashCode() { public int hashCode() {
return super.hashCode(); return super.hashCode();

View File

@ -23,7 +23,7 @@ import org.junit.runners.Parameterized;
import org.libreccm.core.CcmObject; import org.libreccm.core.CcmObject;
import org.libreccm.tests.categories.UnitTest; import org.libreccm.tests.categories.UnitTest;
import org.libreccm.testutils.EqualsVerifier; import org.libreccm.testutils.EqualsVerifier;
import org.libreccm.workflow.UserTask; import org.libreccm.workflow.AssignableTask;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -88,10 +88,10 @@ public class EqualsAndHashCodeTest extends EqualsVerifier {
ccmObject1.setObjectId(-200); ccmObject1.setObjectId(-200);
ccmObject1.setDisplayName("Object 2"); ccmObject1.setDisplayName("Object 2");
final UserTask task1 = new UserTask(); final AssignableTask task1 = new AssignableTask();
task1.setTaskId(-10); task1.setTaskId(-10);
final UserTask task2 = new UserTask(); final AssignableTask task2 = new AssignableTask();
task2.setTaskId(-20); task2.setTaskId(-20);
verifier verifier
@ -100,7 +100,7 @@ public class EqualsAndHashCodeTest extends EqualsVerifier {
.withPrefabValues(Role.class, role1, role2) .withPrefabValues(Role.class, role1, role2)
.withPrefabValues(Party.class, party1, party2) .withPrefabValues(Party.class, party1, party2)
.withPrefabValues(CcmObject.class, ccmObject1, ccmObject2) .withPrefabValues(CcmObject.class, ccmObject1, ccmObject2)
.withPrefabValues(UserTask.class, task1, task2); .withPrefabValues(AssignableTask.class, task1, task2);
} }
} }

View File

@ -21,6 +21,7 @@ package org.libreccm.workflow;
import org.junit.experimental.categories.Category; import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Parameterized; import org.junit.runners.Parameterized;
import org.libreccm.core.CcmObject;
import org.libreccm.security.Group; import org.libreccm.security.Group;
import org.libreccm.security.Role; import org.libreccm.security.Role;
import org.libreccm.security.User; import org.libreccm.security.User;
@ -43,8 +44,9 @@ public class EqualsAndHashCodeTest extends EqualsVerifier {
public static Collection<Class<?>> data() { public static Collection<Class<?>> data() {
return Arrays.asList(new Class<?>[]{ return Arrays.asList(new Class<?>[]{
Task.class, Task.class,
TaskComment.class,
TaskAssignment.class, TaskAssignment.class,
UserTask.class, AssignableTask.class,
Workflow.class, Workflow.class,
WorkflowTemplate.class WorkflowTemplate.class
}); });
@ -60,10 +62,10 @@ public class EqualsAndHashCodeTest extends EqualsVerifier {
super.addPrefabValues(verifier); super.addPrefabValues(verifier);
final UserTask userTask1 = new UserTask(); final AssignableTask userTask1 = new AssignableTask();
userTask1.setTaskId(-10); userTask1.setTaskId(-10);
final UserTask userTask2 = new UserTask(); final AssignableTask userTask2 = new AssignableTask();
userTask2.setTaskId(-20); userTask2.setTaskId(-20);
final Role role1 = new Role(); final Role role1 = new Role();
@ -90,19 +92,33 @@ public class EqualsAndHashCodeTest extends EqualsVerifier {
final User user2 = new TestUser(); final User user2 = new TestUser();
user2.setName("user2"); 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(); final WorkflowTemplate template1 = new WorkflowTemplate();
template1.getName().addValue(Locale.ENGLISH, "Template 1"); template1.getName().addValue(Locale.ENGLISH, "Template 1");
final WorkflowTemplate template2 = new WorkflowTemplate(); final WorkflowTemplate template2 = new WorkflowTemplate();
template1.getName().addValue(Locale.ENGLISH, "Template 2"); 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 verifier
.withPrefabValues(UserTask.class, userTask1, userTask2) .withPrefabValues(AssignableTask.class, userTask1, userTask2)
.withPrefabValues(Role.class, role1, role2) .withPrefabValues(Role.class, role1, role2)
.withPrefabValues(Task.class, task1, task2) .withPrefabValues(Task.class, task1, task2)
.withPrefabValues(Group.class, group1, group2) .withPrefabValues(Group.class, group1, group2)
.withPrefabValues(User.class, user1, user2) .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);
} }
/** /**

View File

@ -40,7 +40,7 @@ public class ToStringTest extends ToStringVerifier {
return Arrays.asList(new Class<?>[]{ return Arrays.asList(new Class<?>[]{
Task.class, Task.class,
TaskAssignment.class, TaskAssignment.class,
UserTask.class, AssignableTask.class,
Workflow.class Workflow.class
}); });
} }

View File

@ -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 ( create table CCM_CORE.APPLICATIONS (
APPLICATION_TYPE varchar(1024) not null, APPLICATION_TYPE varchar(1024) not null,
@ -500,8 +494,8 @@ CREATE SCHEMA ccm_core;
NAME varchar(512) not null, NAME varchar(512) not null,
SETTING_VALUE_DOUBLE double, SETTING_VALUE_DOUBLE double,
SETTING_VALUE_BOOLEAN boolean, SETTING_VALUE_BOOLEAN boolean,
SETTING_VALUE_BIG_DECIMAL decimal(19,2),
SETTING_VALUE_LONG bigint, SETTING_VALUE_LONG bigint,
SETTING_VALUE_BIG_DECIMAL decimal(19,2),
SETTING_VALUE_STRING varchar(1024), SETTING_VALUE_STRING varchar(1024),
primary key (SETTING_ID) primary key (SETTING_ID)
); );
@ -556,6 +550,17 @@ CREATE SCHEMA ccm_core;
primary key (PARTY_ID) 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 ( create table CCM_CORE.WORKFLOW_DESCRIPTIONS (
WORKFLOW_ID bigint not null, WORKFLOW_ID bigint not null,
LOCALIZED_VALUE longvarchar, LOCALIZED_VALUE longvarchar,
@ -571,8 +576,11 @@ CREATE SCHEMA ccm_core;
); );
create table CCM_CORE.WORKFLOW_TASK_COMMENTS ( create table CCM_CORE.WORKFLOW_TASK_COMMENTS (
TASK_ID bigint not null, COMMENT_ID bigint not null,
COMMENT clob COMMENT longvarchar,
AUTHOR_ID bigint,
TASK_ID bigint,
primary key (COMMENT_ID)
); );
create table CCM_CORE.WORKFLOW_TASK_DEPENDENCIES ( create table CCM_CORE.WORKFLOW_TASK_DEPENDENCIES (
@ -607,19 +615,11 @@ CREATE SCHEMA ccm_core;
primary key (WORKFLOW_ID) 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 ( create table CCM_CORE.WORKFLOWS (
WORKFLOW_ID bigint not null, WORKFLOW_ID bigint not null,
ACTIVE boolean,
WORKFLOW_STATE varchar(255),
OBJECT_ID bigint,
TEMPLATE_ID bigint, TEMPLATE_ID bigint,
primary key (WORKFLOW_ID) primary key (WORKFLOW_ID)
); );
@ -1054,9 +1054,9 @@ create sequence hibernate_sequence start with 1 increment by 1;
references CCM_CORE.CCM_ROLES; references CCM_CORE.CCM_ROLES;
alter table CCM_CORE.TASK_ASSIGNMENTS alter table CCM_CORE.TASK_ASSIGNMENTS
add constraint FKc1vovbjg9mp5yegx2fdoutx7u add constraint FKk6gl2yvqr7gnqq25s1bm2gy4i
foreign key (TASK_ID) foreign key (TASK_ID)
references CCM_CORE.WORKFLOW_USER_TASKS; references CCM_CORE.WORKFLOW_ASSIGNABLE_TASKS;
alter table CCM_CORE.THREADS alter table CCM_CORE.THREADS
add constraint FKsx08mpwvwnw97uwdgjs76q39g add constraint FKsx08mpwvwnw97uwdgjs76q39g
@ -1078,6 +1078,21 @@ create sequence hibernate_sequence start with 1 increment by 1;
foreign key (PARTY_ID) foreign key (PARTY_ID)
references CCM_CORE.PARTIES; 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 alter table CCM_CORE.WORKFLOW_DESCRIPTIONS
add constraint FKgx7upkqky82dpxvbs95imfl9l add constraint FKgx7upkqky82dpxvbs95imfl9l
foreign key (WORKFLOW_ID) foreign key (WORKFLOW_ID)
@ -1088,6 +1103,11 @@ create sequence hibernate_sequence start with 1 increment by 1;
foreign key (WORKFLOW_ID) foreign key (WORKFLOW_ID)
references CCM_CORE.WORKFLOWS; 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 alter table CCM_CORE.WORKFLOW_TASK_COMMENTS
add constraint FKkfqrf9jdvm7livu5if06w0r5t add constraint FKkfqrf9jdvm7livu5if06w0r5t
foreign key (TASK_ID) foreign key (TASK_ID)
@ -1123,20 +1143,10 @@ create sequence hibernate_sequence start with 1 increment by 1;
foreign key (WORKFLOW_ID) foreign key (WORKFLOW_ID)
references CCM_CORE.WORKFLOWS; references CCM_CORE.WORKFLOWS;
alter table CCM_CORE.WORKFLOW_USER_TASKS alter table CCM_CORE.WORKFLOWS
add constraint FKf09depwj5rgso2dair07vnu33 add constraint FKrm2yfrs6veoxoy304upq2wc64
foreign key (LOCKING_USER_ID) foreign key (OBJECT_ID)
references CCM_CORE.USERS; references CCM_CORE.CCM_OBJECTS;
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 alter table CCM_CORE.WORKFLOWS
add constraint FKeixdxau4jebw682gd49tdbsjy add constraint FKeixdxau4jebw682gd49tdbsjy

View File

@ -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 ( create table CCM_CORE.APPLICATIONS (
APPLICATION_TYPE varchar(1024) not null, APPLICATION_TYPE varchar(1024) not null,
@ -499,8 +494,8 @@ CREATE SCHEMA ccm_core;
NAME varchar(512) not null, NAME varchar(512) not null,
SETTING_VALUE_DOUBLE float8, SETTING_VALUE_DOUBLE float8,
SETTING_VALUE_BOOLEAN boolean, SETTING_VALUE_BOOLEAN boolean,
SETTING_VALUE_BIG_DECIMAL numeric(19, 2),
SETTING_VALUE_LONG int8, SETTING_VALUE_LONG int8,
SETTING_VALUE_BIG_DECIMAL numeric(19, 2),
SETTING_VALUE_STRING varchar(1024), SETTING_VALUE_STRING varchar(1024),
primary key (SETTING_ID) primary key (SETTING_ID)
); );
@ -555,6 +550,17 @@ CREATE SCHEMA ccm_core;
primary key (PARTY_ID) 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 ( create table CCM_CORE.WORKFLOW_DESCRIPTIONS (
WORKFLOW_ID int8 not null, WORKFLOW_ID int8 not null,
LOCALIZED_VALUE text, LOCALIZED_VALUE text,
@ -570,8 +576,11 @@ CREATE SCHEMA ccm_core;
); );
create table CCM_CORE.WORKFLOW_TASK_COMMENTS ( create table CCM_CORE.WORKFLOW_TASK_COMMENTS (
TASK_ID int8 not null, COMMENT_ID int8 not null,
COMMENT text COMMENT text,
AUTHOR_ID int8,
TASK_ID int8,
primary key (COMMENT_ID)
); );
create table CCM_CORE.WORKFLOW_TASK_DEPENDENCIES ( create table CCM_CORE.WORKFLOW_TASK_DEPENDENCIES (
@ -606,19 +615,11 @@ CREATE SCHEMA ccm_core;
primary key (WORKFLOW_ID) 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 ( create table CCM_CORE.WORKFLOWS (
WORKFLOW_ID int8 not null, WORKFLOW_ID int8 not null,
ACTIVE boolean,
WORKFLOW_STATE varchar(255),
OBJECT_ID int8,
TEMPLATE_ID int8, TEMPLATE_ID int8,
primary key (WORKFLOW_ID) primary key (WORKFLOW_ID)
); );
@ -1053,9 +1054,9 @@ create sequence hibernate_sequence start 1 increment 1;
references CCM_CORE.CCM_ROLES; references CCM_CORE.CCM_ROLES;
alter table CCM_CORE.TASK_ASSIGNMENTS alter table CCM_CORE.TASK_ASSIGNMENTS
add constraint FKc1vovbjg9mp5yegx2fdoutx7u add constraint FKk6gl2yvqr7gnqq25s1bm2gy4i
foreign key (TASK_ID) foreign key (TASK_ID)
references CCM_CORE.WORKFLOW_USER_TASKS; references CCM_CORE.WORKFLOW_ASSIGNABLE_TASKS;
alter table CCM_CORE.THREADS alter table CCM_CORE.THREADS
add constraint FKsx08mpwvwnw97uwdgjs76q39g add constraint FKsx08mpwvwnw97uwdgjs76q39g
@ -1077,6 +1078,21 @@ create sequence hibernate_sequence start 1 increment 1;
foreign key (PARTY_ID) foreign key (PARTY_ID)
references CCM_CORE.PARTIES; 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 alter table CCM_CORE.WORKFLOW_DESCRIPTIONS
add constraint FKgx7upkqky82dpxvbs95imfl9l add constraint FKgx7upkqky82dpxvbs95imfl9l
foreign key (WORKFLOW_ID) foreign key (WORKFLOW_ID)
@ -1087,6 +1103,11 @@ create sequence hibernate_sequence start 1 increment 1;
foreign key (WORKFLOW_ID) foreign key (WORKFLOW_ID)
references CCM_CORE.WORKFLOWS; 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 alter table CCM_CORE.WORKFLOW_TASK_COMMENTS
add constraint FKkfqrf9jdvm7livu5if06w0r5t add constraint FKkfqrf9jdvm7livu5if06w0r5t
foreign key (TASK_ID) foreign key (TASK_ID)
@ -1122,20 +1143,10 @@ create sequence hibernate_sequence start 1 increment 1;
foreign key (WORKFLOW_ID) foreign key (WORKFLOW_ID)
references CCM_CORE.WORKFLOWS; references CCM_CORE.WORKFLOWS;
alter table CCM_CORE.WORKFLOW_USER_TASKS alter table CCM_CORE.WORKFLOWS
add constraint FKf09depwj5rgso2dair07vnu33 add constraint FKrm2yfrs6veoxoy304upq2wc64
foreign key (LOCKING_USER_ID) foreign key (OBJECT_ID)
references CCM_CORE.USERS; references CCM_CORE.CCM_OBJECTS;
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 alter table CCM_CORE.WORKFLOWS
add constraint FKeixdxau4jebw682gd49tdbsjy add constraint FKeixdxau4jebw682gd49tdbsjy