diff --git a/ccm-core/src/main/java/org/libreccm/workflow/TaskComment.java b/ccm-core/src/main/java/org/libreccm/workflow/TaskComment.java
index 3260dffac..8f5e13021 100644
--- a/ccm-core/src/main/java/org/libreccm/workflow/TaskComment.java
+++ b/ccm-core/src/main/java/org/libreccm/workflow/TaskComment.java
@@ -35,28 +35,48 @@ import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.OneToOne;
import javax.persistence.Table;
+import javax.validation.constraints.NotNull;
+import org.libreccm.core.Identifiable;
/**
+ * A comment for a task. Comments are intended for other users, for example to
+ * inform them about problems etc. with the object.
*
* @author Jens Pelzetter
*/
@Entity
@Table(name = "WORKFLOW_TASK_COMMENTS", schema = CoreConstants.DB_SCHEMA)
-public class TaskComment implements Serializable {
+public class TaskComment implements Identifiable, Serializable {
private static final long serialVersionUID = 3842991529698351698L;
+ /**
+ * Database ID of the comment.
+ */
@Id
@Column(name = "COMMENT_ID")
@GeneratedValue(strategy = GenerationType.AUTO)
private long commentId;
+ /**
+ * The UUID of the comment.
+ */
+ @Column(name = "uuid", unique = true, nullable = false)
+ @NotNull
+ private String uuid;
+
+ /**
+ * The comment.
+ */
@Column(name = "COMMENT")
@Basic
@Lob
@Type(type = "org.hibernate.type.TextType")
private String comment;
+ /**
+ * The author of the comment.
+ */
@OneToOne
@JoinColumn(name = "AUTHOR_ID")
private User author;
@@ -69,6 +89,15 @@ public class TaskComment implements Serializable {
this.commentId = commentId;
}
+ @Override
+ public String getUuid() {
+ return uuid;
+ }
+
+ protected void setUuid(final String uuid) {
+ this.uuid = uuid;
+ }
+
public String getComment() {
return comment;
}
@@ -89,6 +118,7 @@ public class TaskComment implements Serializable {
public int hashCode() {
int hash = 3;
hash = 67 * hash + (int) (commentId ^ (commentId >>> 32));
+ hash = 67 * hash + Objects.hashCode(uuid);
hash = 67 * hash + Objects.hashCode(comment);
hash = 67 * hash + Objects.hashCode(author);
return hash;
@@ -113,6 +143,9 @@ public class TaskComment implements Serializable {
if (commentId != other.getCommentId()) {
return false;
}
+ if (!Objects.equals(uuid, other.getUuid())) {
+ return false;
+ }
if (!Objects.equals(comment, other.getComment())) {
return false;
}
@@ -130,12 +163,14 @@ public class TaskComment implements Serializable {
public String toString(final String data) {
return String.format("%s{ "
- + "commentId = %d, "
- + "comment = \"%s\", "
- + "author = %s%s"
- + " }",
+ + "commentId = %d, "
+ + "uuid = \"%s\""
+ + "comment = \"%s\", "
+ + "author = %s%s"
+ + " }",
super.toString(),
commentId,
+ uuid,
comment,
Objects.toString(author),
data);
diff --git a/ccm-core/src/main/java/org/libreccm/workflow/TaskManager.java b/ccm-core/src/main/java/org/libreccm/workflow/TaskManager.java
index 463ea6a3a..b1002d799 100644
--- a/ccm-core/src/main/java/org/libreccm/workflow/TaskManager.java
+++ b/ccm-core/src/main/java/org/libreccm/workflow/TaskManager.java
@@ -23,22 +23,20 @@ import org.apache.logging.log4j.Logger;
import org.libreccm.core.CoreConstants;
import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.RequiresPrivilege;
-import org.libreccm.security.Role;
-import org.libreccm.security.RoleRepository;
import org.libreccm.security.Shiro;
import org.libreccm.security.User;
-import java.util.List;
import java.util.Objects;
-import java.util.stream.Collectors;
+import java.util.UUID;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
-import javax.persistence.TypedQuery;
import javax.transaction.Transactional;
/**
+ * Manager for {@link Task}s. The logic of some of this methods has been taken
+ * from the old implementation without changes.
*
* @author Jens Pelzetter
*/
@@ -46,7 +44,7 @@ import javax.transaction.Transactional;
public class TaskManager {
private static final Logger LOGGER = LogManager.getLogger(TaskManager.class);
-
+
@Inject
private EntityManager entityManager;
@@ -56,12 +54,15 @@ public class TaskManager {
@Inject
private TaskRepository taskRepo;
- @Inject
- private RoleRepository roleRepo;
-
@Inject
private Shiro shiro;
+ /**
+ * Adds a {@link Task} to a {@link Workflow}.
+ *
+ * @param workflow The workflow to which the task is added.
+ * @param task The task to add.
+ */
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
@@ -73,6 +74,12 @@ public class TaskManager {
taskRepo.save(task);
}
+ /**
+ * Removes a {@link Task} from a {@link Workflow}.
+ *
+ * @param workflow The workflow from which the task is removed.
+ * @param task The task to remove.
+ */
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
@@ -84,11 +91,19 @@ public class TaskManager {
taskRepo.save(task);
}
+ /**
+ * Adds a dependent {@link Task} to another {@code Task}.
+ *
+ * @param parent The task to which the dependent task is added.
+ * @param task The dependent task.
+ * @throws CircularTaskDependencyException If a circular dependency is
+ * detected.
+ */
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
public void addDependentTask(final Task parent, final Task task)
- throws CircularTaskDependencyException {
+ throws CircularTaskDependencyException {
checkForCircularDependencies(parent, task);
@@ -99,6 +114,12 @@ public class TaskManager {
taskRepo.save(parent);
}
+ /**
+ * Removes a dependent task.
+ *
+ * @param parent The task from which the dependent task is removed.
+ * @param task The dependent task to remove.
+ */
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
@@ -110,9 +131,16 @@ public class TaskManager {
taskRepo.save(parent);
}
+ /**
+ * Helper method for checking for circular dependencies.
+ *
+ * @param task1
+ * @param task2
+ * @throws CircularTaskDependencyException
+ */
private void checkForCircularDependencies(final Task task1,
final Task task2)
- throws CircularTaskDependencyException {
+ throws CircularTaskDependencyException {
if (dependsOn(task1, task2)) {
throw new CircularTaskDependencyException();
@@ -126,7 +154,7 @@ public class TaskManager {
}
if (current.getDependsOn() != null
- && !current.getDependsOn().isEmpty()) {
+ && !current.getDependsOn().isEmpty()) {
return dependsOn(current, dependsOn);
}
}
@@ -134,30 +162,57 @@ public class TaskManager {
return false;
}
+ /**
+ * Adds a new {@link TaskComment} containing the provided comment to a
+ * {@link Task}. The author of the comment is the current user.
+ *
+ * @param task The task to which the comment is added.
+ * @param comment The comment to add.
+ */
public void addComment(final Task task, final String comment) {
addComment(task, shiro.getUser(), comment);
}
+ /**
+ * Adds a new {@link TaskComment} containing the provided comment to a
+ * {@link Task}.
+ *
+ * @param task The task to which the comment is added.
+ * @param author the author of the comment.
+ * @param comment The comment to add.
+ */
public void addComment(final Task task,
final User author,
final String comment) {
final TaskComment taskComment = new TaskComment();
+ taskComment.setUuid(UUID.randomUUID().toString());
taskComment.setAuthor(author);
taskComment.setComment(comment);
-
+
task.addComment(taskComment);
-
+
entityManager.persist(taskComment);
taskRepo.save(task);
}
+ /**
+ * Removes a comment from a task.
+ *
+ * @param task The task from which the comment is removed.
+ * @param comment The comment to remove.
+ */
public void removeComment(final Task task, final TaskComment comment) {
task.removeComment(comment);
taskRepo.save(task);
}
+ /**
+ * Enables a {@link Task}.
+ *
+ * @param task The task to enable.
+ */
public void enable(final Task task) {
- switch(task.getTaskState()) {
+ switch (task.getTaskState()) {
case DISABLED:
task.setTaskState(TaskState.ENABLED);
taskRepo.save(task);
@@ -174,53 +229,70 @@ public class TaskManager {
}
}
+ /**
+ * Disables a {@link Task}.
+ *
+ * @param task The task to disable.
+ */
public void disable(final Task task) {
task.setTaskState(TaskState.DISABLED);
taskRepo.save(task);
}
-
+
+ /**
+ * Finishes a {@link Task}.
+ *
+ * @param task The task to finish.
+ */
public void finish(final Task task) {
if (task == null) {
throw new IllegalArgumentException("Can't finished null...");
}
-
+
if (task.getTaskState() != TaskState.ENABLED) {
throw new IllegalArgumentException(String.format(
- "Task %s is not enabled.",
- Objects.toString(task)));
+ "Task %s is not enabled.",
+ Objects.toString(task)));
}
-
+
task.setTaskState(TaskState.FINISHED);
taskRepo.save(task);
-
+
task.getDependentTasks().forEach(dependent -> updateState(dependent));
}
+ /**
+ * Helper method for updating the state of {@link Task}. Called by
+ * {@link #finish(org.libreccm.workflow.Task)} to update the state of all
+ * dependent tasks.
+ *
+ * @param task
+ */
protected void updateState(final Task task) {
LOGGER.debug("Updating state for task {}...",
Objects.toString(task));
-
+
boolean dependenciesSatisfied = true;
-
+
if (task.getTaskState() == TaskState.DELETED || !task.isActive()) {
return;
}
-
- for(final Task dependsOnTask : task.getDependsOn()) {
+
+ for (final Task dependsOnTask : task.getDependsOn()) {
LOGGER.debug("Checking dependency {}...",
Objects.toString(dependsOnTask));
if (dependsOnTask.getTaskState() != TaskState.FINISHED
- && dependsOnTask.isActive()) {
-
+ && dependsOnTask.isActive()) {
+
LOGGER.debug("Dependency is not yet satisfied.");
-
+
dependenciesSatisfied = false;
break;
}
}
-
+
LOGGER.debug("Dependencies state is {}", dependenciesSatisfied);
-
+
// Rollback case. Previously finished task, but parent tasks
// are re-enabled.
if (task.getTaskState() == TaskState.FINISHED) {
@@ -232,19 +304,19 @@ public class TaskManager {
return;
}
}
-
+
if (task.getTaskState() == TaskState.ENABLED) {
if (!dependenciesSatisfied) {
disable(task);
return;
}
}
-
+
if (task.getTaskState() == TaskState.DISABLED) {
if (dependenciesSatisfied) {
enable(task);
}
}
- }
+ }
}
diff --git a/ccm-core/src/main/java/org/libreccm/workflow/TaskRepository.java b/ccm-core/src/main/java/org/libreccm/workflow/TaskRepository.java
index 696984497..68e13b423 100644
--- a/ccm-core/src/main/java/org/libreccm/workflow/TaskRepository.java
+++ b/ccm-core/src/main/java/org/libreccm/workflow/TaskRepository.java
@@ -23,7 +23,8 @@ import org.libreccm.core.AbstractEntityRepository;
import javax.enterprise.context.RequestScoped;
/**
- *
+ * Repository for {@link Task}s.
+ *
* @author Jens Pelzetter
*/
@RequestScoped
diff --git a/ccm-core/src/main/java/org/libreccm/workflow/TaskState.java b/ccm-core/src/main/java/org/libreccm/workflow/TaskState.java
index 8951cee64..f6e553494 100644
--- a/ccm-core/src/main/java/org/libreccm/workflow/TaskState.java
+++ b/ccm-core/src/main/java/org/libreccm/workflow/TaskState.java
@@ -19,7 +19,8 @@
package org.libreccm.workflow;
/**
- *
+ * The possible states of a {@link Task}.
+ *
* @author Jens Pelzetter
*/
public enum TaskState {
diff --git a/ccm-core/src/main/java/org/libreccm/workflow/Workflow.java b/ccm-core/src/main/java/org/libreccm/workflow/Workflow.java
index a73fde010..9b1ffeda8 100644
--- a/ccm-core/src/main/java/org/libreccm/workflow/Workflow.java
+++ b/ccm-core/src/main/java/org/libreccm/workflow/Workflow.java
@@ -48,8 +48,12 @@ import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
+import javax.validation.constraints.NotNull;
+import org.libreccm.core.Identifiable;
/**
+ * A workflow is a collection of tasks which are performed on an object. Tasks
+ * can depend on each other.
*
* @author Jens Pelzetter
*/
@@ -58,57 +62,93 @@ import javax.persistence.Table;
@Inheritance(strategy = InheritanceType.JOINED)
@NamedQueries({
@NamedQuery(
- name = "Workflow.findForObject",
- query = "SELECT w FROM Workflow w "
- + "WHERE W.object = :object")
+ name = "Workflow.findForObject",
+ query = "SELECT w FROM Workflow w "
+ + "WHERE W.object = :object")
})
-public class Workflow implements Serializable {
+public class Workflow implements Identifiable, Serializable {
private static final long serialVersionUID = 4322500264543325829L;
+ /**
+ * Database id of the workflow.
+ */
@Id
@Column(name = "WORKFLOW_ID")
@GeneratedValue(strategy = GenerationType.AUTO)
private long workflowId;
+ /**
+ * UUID of the workflow.
+ */
+ @Column(name = "uuid", unique = true, nullable = false)
+ @NotNull
+ private String uuid;
+
+ /**
+ * The template which was used the generate the workflow.
+ */
@ManyToOne
@JoinColumn(name = "TEMPLATE_ID")
private WorkflowTemplate template;
+ /**
+ * Human readable name of the workflow.
+ */
@Embedded
@AssociationOverride(
- name = "values",
- joinTable = @JoinTable(name = "WORKFLOW_NAMES",
- schema = DB_SCHEMA,
- joinColumns = {
- @JoinColumn(name = "WORKFLOW_ID")}))
+ name = "values",
+ joinTable = @JoinTable(name = "WORKFLOW_NAMES",
+ schema = DB_SCHEMA,
+ joinColumns = {
+ @JoinColumn(name = "WORKFLOW_ID")}))
private LocalizedString name;
+ /**
+ * Description of the workflow.
+ */
@Embedded
@AssociationOverride(
- name = "values",
- joinTable = @JoinTable(name = "WORKFLOW_DESCRIPTIONS",
- schema = DB_SCHEMA,
- joinColumns = {
- @JoinColumn(name = "WORKFLOW_ID")
- }))
+ name = "values",
+ joinTable = @JoinTable(name = "WORKFLOW_DESCRIPTIONS",
+ schema = DB_SCHEMA,
+ joinColumns = {
+ @JoinColumn(name = "WORKFLOW_ID")
+ }))
private LocalizedString description;
+ /**
+ * The current state of the workflow.
+ */
@Column(name = "WORKFLOW_STATE")
@Enumerated(EnumType.STRING)
private WorkflowState state;
+ /**
+ * Is the workflow active?
+ */
@Column(name = "ACTIVE")
private boolean active;
+ /**
+ * The task state of the workflow. This field is a leftover from the old
+ * implementation of workflow were workflow extended {@link Task}. Because
+ * we wanted to keep the basic logic this field is here.
+ */
@Column(name = "TASKS_STATE")
@Enumerated(EnumType.STRING)
private TaskState tasksState;
-
+
+ /**
+ * The object for which this workflow was generated.
+ */
@OneToOne
@JoinColumn(name = "OBJECT_ID")
private CcmObject object;
+ /**
+ * The tasks belonging to this workflow.
+ */
@OneToMany(mappedBy = "workflow")
private List tasks;
@@ -124,10 +164,19 @@ public class Workflow implements Serializable {
return workflowId;
}
- public void setWorkflowId(final long workflowId) {
+ protected void setWorkflowId(final long workflowId) {
this.workflowId = workflowId;
}
+ @Override
+ public String getUuid() {
+ return uuid;
+ }
+
+ protected void setUuid(final String uuid) {
+ this.uuid = uuid;
+ }
+
public WorkflowTemplate getTemplate() {
return template;
}
@@ -171,11 +220,11 @@ public class Workflow implements Serializable {
public TaskState getTasksState() {
return tasksState;
}
-
+
protected void setTasksState(final TaskState tasksState) {
this.tasksState = tasksState;
}
-
+
public CcmObject getObject() {
return object;
}
@@ -207,8 +256,9 @@ public class Workflow implements Serializable {
@Override
public int hashCode() {
int hash = 5;
- hash = 79 * hash + (int) (this.workflowId ^ (this.workflowId >>> 32));
- hash = 79 * hash + Objects.hashCode(this.name);
+ hash = 79 * hash + (int) (workflowId ^ (workflowId >>> 32));
+ hash = 79 * hash + Objects.hashCode(uuid);
+ hash = 79 * hash + Objects.hashCode(name);
hash = 79 * hash + Objects.hashCode(description);
hash = 79 * hash + Objects.hashCode(state);
hash = 79 * hash + (active ? 1 : 0);
@@ -234,6 +284,10 @@ public class Workflow implements Serializable {
return false;
}
+ if (!Objects.equals(uuid, other.getUuid())) {
+ return false;
+ }
+
if (!Objects.equals(name, other.getName())) {
return false;
}
@@ -249,7 +303,7 @@ public class Workflow implements Serializable {
if (active != other.isActive()) {
return false;
}
-
+
if (!Objects.equals(tasksState, other.getTasksState())) {
return false;
}
@@ -269,15 +323,17 @@ public class Workflow implements Serializable {
public String toString(final String data) {
return String.format("%s{ "
- + "workflowId = %d, "
- + "name = \"%s\", "
- + "description = \"%s\", "
- + "state = \"%s\", "
- + "active = %b"
- + "object = \"%s\"%s"
- + " }",
+ + "workflowId = %d, "
+ + "uuid = \"%s\", "
+ + "name = \"%s\", "
+ + "description = \"%s\", "
+ + "state = \"%s\", "
+ + "active = %b"
+ + "object = \"%s\"%s"
+ + " }",
super.toString(),
workflowId,
+ uuid,
Objects.toString(name),
Objects.toString(description),
Objects.toString(state),
diff --git a/ccm-core/src/main/java/org/libreccm/workflow/WorkflowConstants.java b/ccm-core/src/main/java/org/libreccm/workflow/WorkflowConstants.java
deleted file mode 100644
index c6c3aa45c..000000000
--- a/ccm-core/src/main/java/org/libreccm/workflow/WorkflowConstants.java
+++ /dev/null
@@ -1,37 +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.libreccm.workflow;
-
-/**
- *
- * @author Jens Pelzetter
- */
-public final class WorkflowConstants {
-
- private WorkflowConstants() {
- //Nothing
- }
-
- public final static int NONE = -1;
- public final static int STARTED = 0;
- public final static int STOPPED = 1;
- public final static int DELETED = 2;
- public final static int INIT = 3;
-
-}
diff --git a/ccm-core/src/main/java/org/libreccm/workflow/WorkflowManager.java b/ccm-core/src/main/java/org/libreccm/workflow/WorkflowManager.java
index 642d7c486..14f1603be 100644
--- a/ccm-core/src/main/java/org/libreccm/workflow/WorkflowManager.java
+++ b/ccm-core/src/main/java/org/libreccm/workflow/WorkflowManager.java
@@ -49,8 +49,18 @@ import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.transaction.Transactional;
+import org.apache.shiro.subject.Subject;
/**
+ * Manager for {@link Workflow}s. The logic of some of these classes has been
+ * ported from the workflow implementation. The methods have only been edited to
+ * fit into the new architecture.
+ *
+ * Most of the methods of this manager require the {@code ADMIN} privilege. To
+ * use this methods with other users the caller has the check the permissions
+ * first and than wrap the call to the method of this class into a new context
+ * with the system user by using
+ * {@link Subject#execute(java.util.concurrent.Callable)}.
*
* @author Jens Pelzetter
*/
@@ -58,7 +68,7 @@ import javax.transaction.Transactional;
public class WorkflowManager {
private final static Logger LOGGER = LogManager.getLogger(
- WorkflowManager.class);
+ WorkflowManager.class);
@Inject
private EntityManager entityManager;
@@ -80,28 +90,49 @@ public class WorkflowManager {
private Locale defaultLocale;
+ /**
+ * Populates the {@link #defaultLocale} field.
+ */
@PostConstruct
private void init() {
final KernelConfig kernelConfig = confManager.findConfiguration(
- KernelConfig.class);
+ KernelConfig.class);
defaultLocale = kernelConfig.getDefaultLocale();
}
+ /**
+ * Creates an {@link Workflow} for the provided {@link CcmObject} using the
+ * provided {@link WorkflowTemplate}.
+ *
+ * @param template The template which is used to create the new workflow.
+ * @param object The object for which th workflow is generated.
+ * @return The new workflow.
+ */
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
public Workflow createWorkflow(final WorkflowTemplate template,
final CcmObject object) {
+ if (template == null) {
+ throw new IllegalArgumentException(
+ "Can't create a workflow without a template.");
+ }
+
+ if (object == null) {
+ throw new IllegalArgumentException(
+ "Can't create a workflow without an object.");
+ }
+
final Workflow workflow = new Workflow();
final LocalizedString name = new LocalizedString();
template.getName().getValues().forEach(
- (locale, str) -> name.addValue(locale, str));
+ (locale, str) -> name.addValue(locale, str));
workflow.setName(name);
final LocalizedString description = new LocalizedString();
template.getDescription().getValues().forEach(
- (locale, str) -> description.addValue(locale, str));
+ (locale, str) -> description.addValue(locale, str));
workflow.setDescription(description);
final Map tasks = new HashMap<>();
@@ -109,7 +140,7 @@ public class WorkflowManager {
template.getTasks().forEach(taskTemplate -> createTask(taskTemplate,
tasks));
template.getTasks().forEach(taskTemplate -> fixTaskDependencies(
- taskTemplate, tasks.get(taskTemplate.getTaskId()), tasks));
+ taskTemplate, tasks.get(taskTemplate.getTaskId()), tasks));
workflow.setObject(object);
workflow.setState(WorkflowState.INIT);
@@ -120,6 +151,15 @@ public class WorkflowManager {
return workflow;
}
+ /**
+ * Helper method for
+ * {@link #createWorkflow(org.libreccm.workflow.WorkflowTemplate, org.libreccm.core.CcmObject)}
+ * for creating the tasks of the new workflow from the tasks of the workflow
+ * template.
+ *
+ * @param template The template for the task from the workflow template.
+ * @param tasks A map for storing the new tasks.
+ */
private void createTask(final Task template, final Map tasks) {
final Class extends Task> templateClass = template.getClass();
final Task task;
@@ -137,14 +177,14 @@ public class WorkflowManager {
}
for (PropertyDescriptor propertyDesc : templateBeanInfo
- .getPropertyDescriptors()) {
+ .getPropertyDescriptors()) {
try {
if ("taskId".equals(propertyDesc.getName())
- || "workflow".equals(propertyDesc.getName())
- || "dependentTasks".equals(propertyDesc.getName())
- || "dependsOn".equals(propertyDesc.getName())
- || "assignments".equals(propertyDesc.getName())
- || "class".equals(propertyDesc.getName())) {
+ || "workflow".equals(propertyDesc.getName())
+ || "dependentTasks".equals(propertyDesc.getName())
+ || "dependsOn".equals(propertyDesc.getName())
+ || "assignments".equals(propertyDesc.getName())
+ || "class".equals(propertyDesc.getName())) {
continue;
}
@@ -161,15 +201,15 @@ public class WorkflowManager {
final LocalizedString copy = new LocalizedString();
localized.getValues().forEach(
- (locale, str) -> copy.addValue(locale, str));
+ (locale, str) -> copy.addValue(locale, str));
writeMethod.invoke(task, copy);
} else {
writeMethod.invoke(task, value);
}
} catch (IllegalAccessException
- | IllegalArgumentException
- | InvocationTargetException ex) {
+ | IllegalArgumentException
+ | InvocationTargetException ex) {
throw new RuntimeException();
}
@@ -177,64 +217,100 @@ public class WorkflowManager {
}
}
+ /**
+ * Helper method for
+ * {@link #createWorkflow(org.libreccm.workflow.WorkflowTemplate, org.libreccm.core.CcmObject)}
+ * and {@link #createTask(org.libreccm.workflow.Task, java.util.Map)} for
+ * creating the task dependencies.
+ *
+ * @param template
+ * @param task
+ * @param tasks
+ */
private void fixTaskDependencies(final Task template,
final Task task,
final Map tasks) {
if (template.getDependentTasks() != null
- && !template.getDependentTasks().isEmpty()) {
+ && !template.getDependentTasks().isEmpty()) {
template.getDependentTasks().forEach(dependent
- -> task.addDependentTask(tasks.get(dependent.getTaskId())));
+ -> task.addDependentTask(tasks.get(dependent.getTaskId())));
}
if (template.getDependsOn() != null
- && !template.getDependsOn().isEmpty()) {
+ && !template.getDependsOn().isEmpty()) {
template.getDependsOn().forEach(dependsOn
- -> task.addDependsOn(tasks.get(dependsOn.getTaskId())));
+ -> task.addDependsOn(tasks.get(dependsOn.getTaskId())));
}
}
+ /**
+ * Finds the enabled {@link Task}s of a {@link Workflow}.
+ *
+ * @param workflow The workflow.
+ * @return A unmodifiable list of the enabled tasks of the provided
+ * {@code workflow}.
+ */
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
public List findEnabledTasks(final Workflow workflow) {
if (workflow.getState() == WorkflowState.DELETED
- || workflow.getState() == WorkflowState.STOPPED) {
+ || workflow.getState() == WorkflowState.STOPPED) {
LOGGER.debug(String.format("Workflow state is \"%s\". Workflow "
- + "has no enabled tasks.",
+ + "has no enabled tasks.",
workflow.getState().toString()));
return Collections.emptyList();
}
final TypedQuery query = entityManager.createNamedQuery(
- "Task.findEnabledTasks", Task.class);
+ "Task.findEnabledTasks", Task.class);
query.setParameter("workflow", workflow);
return Collections.unmodifiableList(query.getResultList());
}
+ /**
+ * Finds the finished {@link Task}s of a workflow.
+ *
+ * @param workflow The workflow.
+ * @return An unmodifiable list of the finished tasks of the provided
+ * {@code Workflow}.
+ */
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
public List findFinishedTasks(final Workflow workflow) {
final TypedQuery query = entityManager.createNamedQuery(
- "Task.findFinishedTasks", Task.class);
+ "Task.findFinishedTasks", Task.class);
query.setParameter("workflow", workflow);
return Collections.unmodifiableList(query.getResultList());
}
+ /**
+ * Finds the {@link Task}s of a {@link Workflow} which are overdue.
+ *
+ * @param workflow The workflow.
+ * @return A unmodifiable list of the overdue tasks of the provided
+ * {@code workflow}.
+ */
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
public List findOverdueTasks(final Workflow workflow) {
final TypedQuery query = entityManager.createNamedQuery(
- "AssignableTask.findOverdueTasks", AssignableTask.class);
+ "AssignableTask.findOverdueTasks", AssignableTask.class);
query.setParameter("workflow", workflow);
query.setParameter("now", new Date());
return Collections.unmodifiableList(query.getResultList());
}
+ /**
+ * Starts a {@link Workflow}.
+ *
+ * @param workflow The workflow to start.
+ */
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
@@ -255,13 +331,18 @@ public class WorkflowManager {
workflowRepo.save(workflow);
}
+ /**
+ * Helper method for updating the state of a {@link Workflow}.
+ *
+ * @param workflow The workflow to update.
+ */
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
private void updateState(final Workflow workflow) {
if (workflow.getTasksState() == TaskState.ENABLED) {
final TypedQuery query = entityManager.createNamedQuery(
- "Task.countUnfinishedAndActiveTasksForWorkflow", Long.class);
+ "Task.countUnfinishedAndActiveTasksForWorkflow", Long.class);
query.setParameter("workflow", workflow);
final Long result = query.getSingleResult();
@@ -275,7 +356,7 @@ public class WorkflowManager {
if (workflow.getTasksState() == TaskState.FINISHED) {
final TypedQuery query = entityManager.createNamedQuery(
- "Task.countUnfinishedTasksForWorkflow", Long.class);
+ "Task.countUnfinishedTasksForWorkflow", Long.class);
query.setParameter("workflow", workflow);
final Long result = query.getSingleResult();
@@ -286,6 +367,11 @@ public class WorkflowManager {
}
}
+ /**
+ * Stops a workflow.
+ *
+ * @param workflow The workflow to stop.
+ */
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
@@ -294,14 +380,19 @@ public class WorkflowManager {
workflowRepo.save(workflow);
}
+ /**
+ * Finished a {@link Workflow}.
+ *
+ * @param workflow The workflow to finish.
+ */
@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 \"%s\" is not enabled.",
+ workflow.getName().getValue(defaultLocale)));
}
workflow.setTasksState(TaskState.FINISHED);
@@ -309,6 +400,11 @@ public class WorkflowManager {
}
+ /**
+ * Enables a {@link Workflow}.
+ *
+ * @param workflow The workflow to enable.
+ */
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
@@ -331,13 +427,18 @@ public class WorkflowManager {
break;
default:
LOGGER.debug("Workflow \"{}\" has tasksState \"{}\", "
- + "#enable(Workflow) does nothing.",
+ + "#enable(Workflow) does nothing.",
workflow.getName().getValue(defaultLocale),
workflow.getTasksState());
break;
}
}
+ /**
+ * Disables a {@link Workflow}.
+ *
+ * @param workflow The workflow to disable.
+ */
@AuthorizationRequired
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
@Transactional(Transactional.TxType.REQUIRED)
diff --git a/ccm-core/src/main/java/org/libreccm/workflow/WorkflowRepository.java b/ccm-core/src/main/java/org/libreccm/workflow/WorkflowRepository.java
index a09f2918c..198172e16 100644
--- a/ccm-core/src/main/java/org/libreccm/workflow/WorkflowRepository.java
+++ b/ccm-core/src/main/java/org/libreccm/workflow/WorkflowRepository.java
@@ -22,12 +22,14 @@ import org.libreccm.core.AbstractEntityRepository;
import org.libreccm.core.CcmObject;
import java.util.Optional;
+import java.util.UUID;
import javax.enterprise.context.RequestScoped;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;
/**
+ * Repository for {@link Workflow}s.
*
* @author Jens Pelzetter
*/
@@ -43,22 +45,35 @@ public class WorkflowRepository extends AbstractEntityRepository
public boolean isNew(final Workflow workflow) {
return workflow.getWorkflowId() == 0;
}
-
+
+ @Override
+ public void initNewEntity(final Workflow workflow) {
+ workflow.setUuid(UUID.randomUUID().toString());
+ }
+
+ /**
+ * Finds the workflow for an given object if the object has workflow.
+ *
+ * @param object The object
+ * @return An {@link Optional} containing the workflow assigned to the
+ * {@code object} if the object has a workflow. Otherwise an empty
+ * {@link Optional} is returned.
+ */
public Optional findWorkflowForObject(final CcmObject object) {
if (object == null) {
throw new IllegalArgumentException(
- "Can't find a workflow for object null.");
+ "Can't find a workflow for object null.");
}
-
+
final TypedQuery query = getEntityManager().createNamedQuery(
- "Workflow.findForObject", Workflow.class);
+ "Workflow.findForObject", Workflow.class);
query.setParameter("object", object);
-
+
try {
return Optional.of(query.getSingleResult());
- } catch(NoResultException ex) {
+ } catch (NoResultException ex) {
return Optional.empty();
}
}
-
+
}
diff --git a/ccm-core/src/main/java/org/libreccm/workflow/WorkflowState.java b/ccm-core/src/main/java/org/libreccm/workflow/WorkflowState.java
index 9cb8541d8..c4872a172 100644
--- a/ccm-core/src/main/java/org/libreccm/workflow/WorkflowState.java
+++ b/ccm-core/src/main/java/org/libreccm/workflow/WorkflowState.java
@@ -19,7 +19,8 @@
package org.libreccm.workflow;
/**
- *
+ * The possible states of a workflow.
+ *
* @author Jens Pelzetter
*/
public enum WorkflowState {
@@ -28,6 +29,6 @@ public enum WorkflowState {
STOPPED,
DELETED,
INIT,
- NONE
+ NONE;
}
diff --git a/ccm-core/src/main/java/org/libreccm/workflow/WorkflowTemplate.java b/ccm-core/src/main/java/org/libreccm/workflow/WorkflowTemplate.java
index 1bbd3f39e..9a3477915 100644
--- a/ccm-core/src/main/java/org/libreccm/workflow/WorkflowTemplate.java
+++ b/ccm-core/src/main/java/org/libreccm/workflow/WorkflowTemplate.java
@@ -28,7 +28,9 @@ import javax.persistence.Entity;
import javax.persistence.Table;
/**
- *
+ * Objects of these class are used as templates for new workflows. The tasks
+ * in the template are copied when a new workflow is generated.
+ *
* @author Jens Pelzetter
*/
@Entity
@@ -37,6 +39,13 @@ public class WorkflowTemplate extends Workflow implements Serializable {
private static final long serialVersionUID = 5770519379144947171L;
+ /**
+ * A workflow template has no object. Therefore the {@code setObject(CcmObject)
+ * method has been overwritten the throw an {@link UnsupportedOperationException}
+ * when called on the workflow template.
+ *
+ * @param object
+ */
@Override
protected void setObject(final CcmObject object) {
throw new UnsupportedOperationException(
diff --git a/ccm-core/src/main/java/org/libreccm/workflow/WorkflowTemplateRepository.java b/ccm-core/src/main/java/org/libreccm/workflow/WorkflowTemplateRepository.java
index 0ebb9c7e6..fed04a3f6 100644
--- a/ccm-core/src/main/java/org/libreccm/workflow/WorkflowTemplateRepository.java
+++ b/ccm-core/src/main/java/org/libreccm/workflow/WorkflowTemplateRepository.java
@@ -23,7 +23,8 @@ import org.libreccm.core.AbstractEntityRepository;
import javax.enterprise.context.RequestScoped;
/**
- *
+ * A repository for {@link WorkflowTemplate}s.
+ *
* @author Jens Pelzetter
*/
@RequestScoped