CCM NG: JavaDoc for Workflow and related classes

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4444 8810af33-2d31-482b-a856-94f89814c4df
pull/2/head
jensp 2016-11-17 16:53:45 +00:00
parent 17a2157b5c
commit 2ae87e3353
16 changed files with 233 additions and 42 deletions

View File

@ -19,6 +19,7 @@
package org.librecms.workflow;
import org.libreccm.workflow.AssignableTask;
import org.librecms.contentsection.ContentItem;
import java.io.Serializable;
import java.util.Objects;
@ -32,7 +33,8 @@ import javax.persistence.Table;
import static org.librecms.CmsConstants.*;
/**
*
* A special tasks for {@link ContentItem}s.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Entity
@ -41,6 +43,9 @@ public class CmsTask extends AssignableTask implements Serializable {
private static final long serialVersionUID = -3988352366529930659L;
/**
* The type of the task.
*/
@Column(name = "TASK_TYPE")
@Enumerated(EnumType.STRING)
private CmsTaskType taskType;

View File

@ -21,18 +21,25 @@ package org.librecms.workflow;
import com.arsdigita.cms.workflow.TaskURLGenerator;
import com.arsdigita.util.UncheckedWrapperException;
import org.libreccm.workflow.AssignableTaskManager;
import org.librecms.contentsection.ContentItem;
import javax.enterprise.context.RequestScoped;
/**
*
* Manager for {@link CmsTask}s.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class CmsTaskManager extends AssignableTaskManager {
public class CmsTaskManager {
/**
* Retrieves the URL for finishing the task for a certain {@link ContentItem}.
*
* @param item The item.
* @param task The task.
* @return The finish URL.
*/
public String getFinishUrl(final ContentItem item, final CmsTask task) {
final Class<? extends TaskURLGenerator> urlGeneratorClass = task
.getTaskType().getUrlGenerator();

View File

@ -26,7 +26,8 @@ import com.arsdigita.cms.workflow.TaskURLGenerator;
import org.librecms.contentsection.privileges.ItemPrivileges;
/**
*
* Possible types of a {@link CmsTask}.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public enum CmsTaskType {

View File

@ -35,6 +35,7 @@ import org.librecms.lifecycle.LifecycleDefinition;
import java.util.Arrays;
import java.util.Collection;
import java.util.Locale;
/**
*
@ -124,30 +125,32 @@ public class EqualsAndHashCodeTest extends EqualsVerifier {
final CcmApplication application2 = new CcmApplication();
application2.setDisplayName("Application 2");
final Domain domain1 = new Domain();
domain1.setDisplayName("Domain 1");
final Domain domain2 = new Domain();
domain2.setDisplayName("Domain 2");
final Resource resource1 = new Resource();
resource1.setDisplayName("Resource 1");
final Resource resource2 = new Resource();
resource2.setDisplayName("Resource 2");
final LifecycleDefinition lifecycleDef1 = new LifecycleDefinition();
lifecycleDef1.setDefinitionId(-100);
final LifecycleDefinition lifecycleDef2 = new LifecycleDefinition();
lifecycleDef2.setDefinitionId(-110);
final WorkflowTemplate workflowTemplate1 = new WorkflowTemplate();
workflowTemplate1.setWorkflowId(-200);
workflowTemplate1.getName().addValue(Locale.ENGLISH,
"Workflow Template 1");
final WorkflowTemplate workflowTemplate2 = new WorkflowTemplate();
workflowTemplate2.setWorkflowId(-210);
workflowTemplate2.getName().addValue(Locale.ENGLISH,
"Workflow Template 2");
verifier
.withPrefabValues(ContentItem.class, item1, item2)
@ -161,11 +164,11 @@ public class EqualsAndHashCodeTest extends EqualsVerifier {
.withPrefabValues(CcmApplication.class, application1, application2)
.withPrefabValues(Domain.class, domain1, domain2)
.withPrefabValues(Resource.class, resource1, resource2)
.withPrefabValues(LifecycleDefinition.class,
lifecycleDef1,
.withPrefabValues(LifecycleDefinition.class,
lifecycleDef1,
lifecycleDef2)
.withPrefabValues(WorkflowTemplate.class,
workflowTemplate1,
.withPrefabValues(WorkflowTemplate.class,
workflowTemplate1,
workflowTemplate2);
}

View File

@ -297,7 +297,7 @@ public abstract class AbstractEntityRepository<K, E> {
*
* @param entity The entity to init.
*/
public void initNewEntity(final E entity) {
protected void initNewEntity(final E entity) {
//Empty default implementation
}

View File

@ -41,7 +41,10 @@ import javax.persistence.Temporal;
import javax.persistence.TemporalType;
/**
*
* A task which can be assigned to a user. Also a {@code AssignableTask} can be
* locked by a user to indicate that the user is currently working on the
* object to which the workflow to which the task belongs is assigned.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Entity
@ -79,29 +82,50 @@ public class AssignableTask extends Task implements Serializable {
private static final long serialVersionUID = 4188064584389893019L;
/**
* Is the task locked?
*/
@Column(name = "LOCKED")
private boolean locked;
/**
* The user which has locked the task (if the task is locked).
*/
@OneToOne
@JoinColumn(name = "LOCKING_USER_ID")
private User lockingUser;
/**
* The date on which the task was started.
*/
@Column(name = "START_DATE")
@Temporal(TemporalType.TIMESTAMP)
private Date startDate;
/**
* The date on which the task should be finished.
*/
@Column(name = "DUE_DATE")
@Temporal(TemporalType.TIMESTAMP)
private Date dueDate;
/**
* How long did it take to complete the task?
*/
@Column(name = "DURATION_MINUTES")
private long durationMinutes;
/**
* Which user should be used as sender of notification emails for the task?
*/
@OneToOne
@JoinColumn(name = "NOTIFICATION_SENDER")
@SuppressWarnings("PMD.LongVariable") //Shorter name would not be descriptive
private User notificationSender;
/**
* The roles to which task is assigned.
*/
@OneToMany(mappedBy = "task")
private List<TaskAssignment> assignments;

View File

@ -41,16 +41,16 @@ import javax.transaction.Transactional;
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class AssignableTaskManager extends TaskManager {
public class AssignableTaskManager {
@Inject
private EntityManager entityManager;
@Inject
private WorkflowRepository workflowRepo;
private TaskRepository taskRepo;
@Inject
private TaskRepository taskRepo;
private TaskManager taskManager;
@Inject
private RoleRepository roleRepo;
@ -58,10 +58,26 @@ public class AssignableTaskManager extends TaskManager {
@Inject
private Shiro shiro;
/**
* Assigns a task to role.
*
* @param task The task to assign.
* @param role The role to which the task is assigned.
*/
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
public void assignTask(final AssignableTask task, final Role role) {
if (task == null) {
throw new IllegalArgumentException(
"Can't assign task null to a role.");
}
if (role == null) {
throw new IllegalArgumentException(
"Can't assign a task to role null.");
}
final TaskAssignment assignment = new TaskAssignment();
assignment.setTask(task);
assignment.setRole(role);
@ -74,10 +90,26 @@ public class AssignableTaskManager extends TaskManager {
roleRepo.save(role);
}
/**
* Deletes a task assignments.
*
* @param task
* @param role
*/
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
public void retractTask(final AssignableTask task, final Role role) {
if (task == null) {
throw new IllegalArgumentException(
"Can't retract task null from a role.");
}
if (role == null) {
throw new IllegalArgumentException(
"Can't retract a task from role null.");
}
final List<TaskAssignment> result = task.getAssignments().stream()
.filter(assigned -> role.equals(assigned.getRole()))
.collect(Collectors.toList());
@ -90,30 +122,65 @@ public class AssignableTaskManager extends TaskManager {
}
}
/**
*
* @param task
*/
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
public void lockTask(final AssignableTask task) {
if (task == null) {
throw new IllegalArgumentException("Can't lock task null.");
}
if (task.isLocked()) {
throw new IllegalArgumentException(String.format(
"Task %s is already locked by user \"%s\".",
Objects.toString(task),
task.getLockingUser().getName()));
}
task.setLocked(true);
task.setLockingUser(shiro.getUser());
taskRepo.save(task);
}
/**
* Unlocks a task.
*
* @param task The task to unlock.
*/
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
public void unlockTask(final AssignableTask task) {
if (task == null) {
throw new IllegalArgumentException("Can't unlock task null.");
}
task.setLocked(false);
task.setLockingUser(null);
taskRepo.save(task);
}
/**
* Retrieves a list of all tasks locked by a specific user.
*
* @param user The user which locks the tasks.
* @return A list with all tasks locked by the specified user.
*/
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
public List<AssignableTask> lockedBy(final User user) {
if (user == null) {
throw new IllegalArgumentException("user can't be null.");
}
final TypedQuery<AssignableTask> query = entityManager.createNamedQuery(
"UserTask.findLockedBy", AssignableTask.class);
query.setParameter("user", user);
@ -121,12 +188,17 @@ public class AssignableTaskManager extends TaskManager {
return query.getResultList();
}
/**
* Finishes a {@link AssignableTask}.
*
* @param task The task to finish.
*/
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
public void finish(final AssignableTask task) {
final User currentUser = shiro.getUser();
if (!currentUser.equals(task.getLockingUser())) {
throw new IllegalArgumentException(String.format(
"Current user %s is not locking user for task %s. Task is"
@ -135,18 +207,23 @@ public class AssignableTaskManager extends TaskManager {
Objects.toString(task),
Objects.toString(task.getLockingUser())));
}
super.finish(task);
taskManager.finish(task);
}
/**
* Finishes a {@link AssignableTask} with a comment.
*
* @param task The task to finish.
* @param comment The comment to add to the task.
*/
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
public void finish(final AssignableTask task,
final String comment) {
addComment(task, comment);
taskManager.addComment(task, comment);
finish(task);
}
}

View File

@ -29,7 +29,8 @@ import javax.enterprise.context.RequestScoped;
import javax.persistence.TypedQuery;
/**
*
* Repository for assignable tasks.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped

View File

@ -20,7 +20,8 @@
package org.libreccm.workflow;
/**
*
* Thrown when a circular task dependency is detected.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class CircularTaskDependencyException extends Exception {

View File

@ -20,6 +20,8 @@ package org.libreccm.workflow;
import static org.libreccm.core.CoreConstants.*;
import org.libreccm.core.CcmObject;
import org.libreccm.core.Identifiable;
import org.libreccm.l10n.LocalizedString;
import java.io.Serializable;
@ -47,8 +49,11 @@ import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
/**
* A task is part of a workflow and represents a specific step in the creation
* process of an {@link CcmObject}.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@ -91,15 +96,28 @@ import javax.persistence.Table;
+ "WHERE t.workflow = :workflow "
+ "AND t.taskState = org.libreccm.workflow.TaskState.FINISHED")
})
public class Task implements Serializable {
public class Task implements Identifiable, Serializable {
private static final long serialVersionUID = 8161343036908150426L;
/**
* Database ID of the task.
*/
@Id
@Column(name = "TASK_ID")
@GeneratedValue(strategy = GenerationType.AUTO)
private long taskId;
/**
* The UUID of the task.
*/
@Column(name = "UUID", unique = true, nullable = false)
@NotNull
private String uuid;
/**
* A human readable, localisable label for the task.
*/
@Embedded
@AssociationOverride(
name = "values",
@ -109,6 +127,9 @@ public class Task implements Serializable {
@JoinColumn(name = "TASK_ID")}))
private LocalizedString label;
/**
* A description of the task.
*/
@Embedded
@AssociationOverride(
name = "values",
@ -118,20 +139,35 @@ public class Task implements Serializable {
@JoinColumn(name = "TASK_ID")}))
private LocalizedString description;
/**
* Is the task active?
*/
@Column(name = "ACTIVE")
private boolean active;
/**
* The state of the task.
*/
@Column(name = "TASK_STATE", length = 512)
@Enumerated(EnumType.STRING)
private TaskState taskState;
/**
* The workflow to which the task belongs.
*/
@ManyToOne
@JoinColumn(name = "WORKFLOW_ID")
private Workflow workflow;
/**
* Tasks which the depends of this task.
*/
@ManyToMany(mappedBy = "dependsOn")
private List<Task> dependentTasks;
/**
* The task of this task depends.
*/
@ManyToMany
@JoinTable(name = "WORKFLOW_TASK_DEPENDENCIES",
schema = DB_SCHEMA,
@ -141,6 +177,9 @@ public class Task implements Serializable {
@JoinColumn(name = "DEPENDENT_TASK_ID")})
private List<Task> dependsOn;
/**
* Comments for the task.
*/
@OneToMany
@JoinColumn(name = "TASK_ID")
private List<TaskComment> comments;
@ -159,10 +198,18 @@ public class Task implements Serializable {
return taskId;
}
public void setTaskId(final long taskId) {
protected void setTaskId(final long taskId) {
this.taskId = taskId;
}
public String getUuid() {
return uuid;
}
protected void setUuid(final String uuid) {
this.uuid = uuid;
}
public LocalizedString getLabel() {
return label;
}
@ -267,6 +314,7 @@ public class Task implements Serializable {
public int hashCode() {
int hash = 7;
hash = 79 * hash + (int) (taskId ^ (taskId >>> 32));
hash = 79 * hash + Objects.hashCode(uuid);
hash = 79 * hash + Objects.hashCode(label);
hash = 79 * hash + Objects.hashCode(description);
hash = 79 * hash + (active ? 1 : 0);
@ -296,6 +344,9 @@ public class Task implements Serializable {
if (taskId != other.getTaskId()) {
return false;
}
if (!Objects.equals(uuid, other.getUuid())) {
return false;
}
if (!Objects.equals(label, other.getLabel())) {
return false;
}
@ -323,6 +374,7 @@ public class Task implements Serializable {
public String toString(final String data) {
return String.format("%s{ "
+ "taskId = %d, "
+ "uuid = \"%s\", "
+ "label = %s, "
+ "active = %b, "
+ "taskState = \"%s\", "
@ -332,6 +384,7 @@ public class Task implements Serializable {
+ " }",
super.toString(),
taskId,
uuid,
Objects.toString(label),
active,
taskState,

View File

@ -35,7 +35,8 @@ import javax.persistence.ManyToOne;
import javax.persistence.Table;
/**
*
* Represents the assignment of a {@link AssignableTask} to a {@link Role}.
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Entity
@ -44,15 +45,24 @@ public class TaskAssignment implements Serializable {
private static final long serialVersionUID = -4427537363301565707L;
/**
* Database ID of the entity.
*/
@Id
@Column(name = "TASK_ASSIGNMENT_ID")
@GeneratedValue(strategy = GenerationType.AUTO)
private long taskAssignmentId;
/**
* The task.
*/
@ManyToOne
@JoinColumn(name = "TASK_ID")
private AssignableTask task;
/**
* The role to which the task is assigned.
*/
@ManyToOne
@JoinColumn(name = "ROLE_ID")
private Role role;

View File

@ -61,7 +61,7 @@ public class TaskComment implements Identifiable, Serializable {
/**
* The UUID of the comment.
*/
@Column(name = "uuid", unique = true, nullable = false)
@Column(name = "UUID", unique = true, nullable = false)
@NotNull
private String uuid;

View File

@ -20,6 +20,8 @@ package org.libreccm.workflow;
import org.libreccm.core.AbstractEntityRepository;
import java.util.UUID;
import javax.enterprise.context.RequestScoped;
/**
@ -39,5 +41,10 @@ public class TaskRepository extends AbstractEntityRepository<Long, Task> {
public boolean isNew(final Task task) {
return task.getTaskId() == 0;
}
@Override
protected void initNewEntity(final Task task) {
super.initNewEntity(task);
task.setUuid(UUID.randomUUID().toString());
}
}

View File

@ -81,7 +81,7 @@ public class Workflow implements Identifiable, Serializable {
/**
* UUID of the workflow.
*/
@Column(name = "uuid", unique = true, nullable = false)
@Column(name = "UUID", unique = true, nullable = false)
@NotNull
private String uuid;

View File

@ -47,7 +47,8 @@ public class WorkflowRepository extends AbstractEntityRepository<Long, Workflow>
}
@Override
public void initNewEntity(final Workflow workflow) {
protected void initNewEntity(final Workflow workflow) {
super.initNewEntity(workflow);
workflow.setUuid(UUID.randomUUID().toString());
}

View File

@ -27,6 +27,7 @@ import org.libreccm.workflow.AssignableTask;
import java.util.Arrays;
import java.util.Collection;
import java.util.Locale;
/**
*
@ -89,10 +90,10 @@ public class EqualsAndHashCodeTest extends EqualsVerifier {
ccmObject1.setDisplayName("Object 2");
final AssignableTask task1 = new AssignableTask();
task1.setTaskId(-10);
task1.getLabel().addValue(Locale.ENGLISH, "Task 1");
final AssignableTask task2 = new AssignableTask();
task2.setTaskId(-20);
task2.getLabel().addValue(Locale.ENGLISH, "Task 2");
verifier
.withPrefabValues(Group.class, group1, group2)