/* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.activiti.engine.impl.persistence.entity; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.activiti.engine.ActivitiException; import org.activiti.engine.delegate.DelegateExecution; import org.activiti.engine.delegate.DelegateTask; import org.activiti.engine.delegate.TaskListener; import org.activiti.engine.impl.context.Context; import org.activiti.engine.impl.db.DbSqlSession; import org.activiti.engine.impl.db.HasRevision; import org.activiti.engine.impl.db.PersistentObject; import org.activiti.engine.impl.delegate.TaskListenerInvocation; import org.activiti.engine.impl.interceptor.CommandContext; import org.activiti.engine.impl.pvm.delegate.ActivityExecution; import org.activiti.engine.impl.task.TaskDefinition; import org.activiti.engine.impl.util.ClockUtil; import org.activiti.engine.task.DelegationState; import org.activiti.engine.task.IdentityLink; import org.activiti.engine.task.IdentityLinkType; import org.activiti.engine.task.Task; /** * @author Tom Baeyens * @author Joram Barrez * @author Falko Menge */ public class TaskEntity extends VariableScopeImpl implements Task, DelegateTask, Serializable, PersistentObject, HasRevision { public static final String DELETE_REASON_COMPLETED = "completed"; public static final String DELETE_REASON_DELETED = "deleted"; private static final long serialVersionUID = 1L; protected int revision; protected String owner; protected String assignee; protected DelegationState delegationState; protected String parentTaskId; protected String name; protected String description; protected int priority = Task.PRIORITY_NORMAL; protected Date createTime; // The time when the task has been created protected Date dueDate; protected int suspensionState = SuspensionState.ACTIVE.getStateCode(); protected boolean isIdentityLinksInitialized = false; protected List<IdentityLinkEntity> taskIdentityLinkEntities = new ArrayList<IdentityLinkEntity>(); protected String executionId; protected ExecutionEntity execution; protected String processInstanceId; protected ExecutionEntity processInstance; protected String processDefinitionId; protected TaskDefinition taskDefinition; protected String taskDefinitionKey; protected boolean isDeleted; protected String eventName; public TaskEntity() { } public TaskEntity(String taskId) { this.id = taskId; } /** creates and initializes a new persistent task. */ public static TaskEntity createAndInsert(ActivityExecution execution) { TaskEntity task = create(); task.insert((ExecutionEntity) execution); return task; } public void insert(ExecutionEntity execution) { CommandContext commandContext = Context.getCommandContext(); DbSqlSession dbSqlSession = commandContext.getDbSqlSession(); dbSqlSession.insert(this); if(execution != null) { execution.addTask(this); } commandContext.getHistoryManager().recordTaskCreated(this, execution); } public void update() { // Needed to make history work: the setter will also update the historic task setOwner(this.getOwner()); setAssignee(this.getAssignee()); setDelegationState(this.getDelegationState()); setName(this.getName()); setDescription(this.getDescription()); setPriority(this.getPriority()); setCreateTime(this.getCreateTime()); setDueDate(this.getDueDate()); setParentTaskId(this.getParentTaskId()); CommandContext commandContext = Context.getCommandContext(); DbSqlSession dbSqlSession = commandContext.getDbSqlSession(); dbSqlSession.update(this); } /** new task. Embedded state and create time will be initialized. * But this task still will have to be persisted with * TransactionContext * .getCurrent() * .getPersistenceSession() * .insert(task); */ public static TaskEntity create() { TaskEntity task = new TaskEntity(); task.isIdentityLinksInitialized = true; task.createTime = ClockUtil.getCurrentTime(); return task; } public void complete() { fireEvent(TaskListener.EVENTNAME_COMPLETE); Context .getCommandContext() .getTaskManager() .deleteTask(this, TaskEntity.DELETE_REASON_COMPLETED, false); if (executionId!=null) { ExecutionEntity execution = getExecution(); execution.removeTask(this); execution.signal(null, null); } } public void delegate(String userId) { setDelegationState(DelegationState.PENDING); if (getOwner() == null) { setOwner(getAssignee()); } setAssignee(userId); } public void resolve() { setDelegationState(DelegationState.RESOLVED); setAssignee(this.owner); } public Object getPersistentState() { Map<String, Object> persistentState = new HashMap<String, Object>(); persistentState.put("assignee", this.assignee); persistentState.put("owner", this.owner); persistentState.put("name", this.name); persistentState.put("priority", this.priority); if (executionId != null) { persistentState.put("executionId", this.executionId); } if (processDefinitionId != null) { persistentState.put("processDefinitionId", this.processDefinitionId); } if (createTime != null) { persistentState.put("createTime", this.createTime); } if(description != null) { persistentState.put("description", this.description); } if(dueDate != null) { persistentState.put("dueDate", this.dueDate); } if (parentTaskId != null) { persistentState.put("parentTaskId", this.parentTaskId); } if (delegationState != null) { persistentState.put("delegationState", this.delegationState); } persistentState.put("suspensionState", this.suspensionState); return persistentState; } public int getRevisionNext() { return revision+1; } // variables //////////////////////////////////////////////////////////////// @Override protected VariableScopeImpl getParentVariableScope() { if (getExecution()!=null) { return execution; } return null; } @Override protected void initializeVariableInstanceBackPointer(VariableInstanceEntity variableInstance) { variableInstance.setTaskId(id); variableInstance.setExecutionId(executionId); variableInstance.setProcessInstanceId(processInstanceId); } @Override protected List<VariableInstanceEntity> loadVariableInstances() { return Context .getCommandContext() .getVariableInstanceManager() .findVariableInstancesByTaskId(id); } // execution //////////////////////////////////////////////////////////////// public ExecutionEntity getExecution() { if ( (execution==null) && (executionId!=null) ) { this.execution = Context .getCommandContext() .getExecutionManager() .findExecutionById(executionId); } return execution; } public void setExecution(DelegateExecution execution) { if (execution!=null) { this.execution = (ExecutionEntity) execution; this.executionId = this.execution.getId(); this.processInstanceId = this.execution.getProcessInstanceId(); this.processDefinitionId = this.execution.getProcessDefinitionId(); Context.getCommandContext().getHistoryManager().recordTaskExecutionIdChange(this.id, executionId); } else { this.execution = null; this.executionId = null; this.processInstanceId = null; this.processDefinitionId = null; throw new ActivitiException("huh?"); } } // task assignment ////////////////////////////////////////////////////////// public IdentityLinkEntity addIdentityLink(String userId, String groupId, String type) { IdentityLinkEntity identityLinkEntity = IdentityLinkEntity.createAndInsert(); getIdentityLinks().add(identityLinkEntity); identityLinkEntity.setTask(this); identityLinkEntity.setUserId(userId); identityLinkEntity.setGroupId(groupId); identityLinkEntity.setType(type); return identityLinkEntity; } public void deleteIdentityLink(String userId, String groupId, String type) { List<IdentityLinkEntity> identityLinks = Context .getCommandContext() .getIdentityLinkManager() .findIdentityLinkByTaskUserGroupAndType(id, userId, groupId, type); for (IdentityLinkEntity identityLink: identityLinks) { Context .getCommandContext() .getDbSqlSession() .delete(identityLink); } } public Set<IdentityLink> getCandidates() { Set<IdentityLink> potentialOwners = new HashSet<IdentityLink>(); for (IdentityLinkEntity identityLinkEntity : getIdentityLinks()) { if (IdentityLinkType.CANDIDATE.equals(identityLinkEntity.getType())) { potentialOwners.add(identityLinkEntity); } } return potentialOwners; } public void addCandidateUser(String userId) { addIdentityLink(userId, null, IdentityLinkType.CANDIDATE); } public void addCandidateUsers(Collection<String> candidateUsers) { for (String candidateUser : candidateUsers) { addCandidateUser(candidateUser); } } public void addCandidateGroup(String groupId) { addIdentityLink(null, groupId, IdentityLinkType.CANDIDATE); } public void addCandidateGroups(Collection<String> candidateGroups) { for (String candidateGroup : candidateGroups) { addCandidateGroup(candidateGroup); } } public void addGroupIdentityLink(String groupId, String identityLinkType) { addIdentityLink(null, groupId, identityLinkType); } public void addUserIdentityLink(String userId, String identityLinkType) { addIdentityLink(userId, null, identityLinkType); } public void deleteCandidateGroup(String groupId) { deleteGroupIdentityLink(groupId, IdentityLinkType.CANDIDATE); } public void deleteCandidateUser(String userId) { deleteUserIdentityLink(userId, IdentityLinkType.CANDIDATE); } public void deleteGroupIdentityLink(String groupId, String identityLinkType) { if (groupId!=null) { deleteIdentityLink(null, groupId, identityLinkType); } } public void deleteUserIdentityLink(String userId, String identityLinkType) { if (userId!=null) { deleteIdentityLink(userId, null, identityLinkType); } } public List<IdentityLinkEntity> getIdentityLinks() { if (!isIdentityLinksInitialized) { taskIdentityLinkEntities = Context .getCommandContext() .getIdentityLinkManager() .findIdentityLinksByTaskId(id); isIdentityLinksInitialized = true; } return taskIdentityLinkEntities; } @SuppressWarnings("unchecked") public Map<String, Object> getActivityInstanceVariables() { if (execution!=null) { return execution.getVariables(); } return Collections.EMPTY_MAP; } public void setExecutionVariables(Map<String, Object> parameters) { if (getExecution()!=null) { execution.setVariables(parameters); } } public String toString() { return "Task["+id+"]"; } // special setters ////////////////////////////////////////////////////////// public void setName(String taskName) { this.name = taskName; CommandContext commandContext = Context.getCommandContext(); if (commandContext!=null) { commandContext .getHistoryManager() .recordTaskNameChange(id, taskName); } } /* plain setter for persistence */ public void setNameWithoutCascade(String taskName) { this.name = taskName; } public void setDescription(String description) { this.description = description; CommandContext commandContext = Context.getCommandContext(); if (commandContext!=null) { commandContext .getHistoryManager() .recordTaskDescriptionChange(id, description); } } /* plain setter for persistence */ public void setDescriptionWithoutCascade(String description) { this.description = description; } public void setAssignee(String assignee) { if (assignee==null && this.assignee==null) { return; } // if (assignee!=null && assignee.equals(this.assignee)) { // return; // } this.assignee = assignee; CommandContext commandContext = Context.getCommandContext(); if (commandContext!=null) { commandContext .getHistoryManager() .recordTaskAssigneeChange(id, assignee); // if there is no command context, then it means that the user is calling the // setAssignee outside a service method. E.g. while creating a new task. if (commandContext!=null) { fireEvent(TaskListener.EVENTNAME_ASSIGNMENT); } } } /* plain setter for persistence */ public void setAssigneeWithoutCascade(String assignee) { this.assignee = assignee; } public void setOwner(String owner) { if (owner==null && this.owner==null) { return; } // if (owner!=null && owner.equals(this.owner)) { // return; // } this.owner = owner; CommandContext commandContext = Context.getCommandContext(); if (commandContext!=null) { commandContext .getHistoryManager() .recordTaskOwnerChange(id, owner); } } /* plain setter for persistence */ public void setOwnerWithoutCascade(String owner) { this.owner = owner; } public void setDueDate(Date dueDate) { this.dueDate = dueDate; CommandContext commandContext = Context.getCommandContext(); if (commandContext!=null) { commandContext .getHistoryManager() .recordTaskDueDateChange(id, dueDate); } } public void setDueDateWithoutCascade(Date dueDate) { this.dueDate = dueDate; } public void setPriority(int priority) { this.priority = priority; CommandContext commandContext = Context.getCommandContext(); if (commandContext!=null) { commandContext .getHistoryManager() .recordTaskPriorityChange(id, priority); } } public void setPriorityWithoutCascade(int priority) { this.priority = priority; } public void setParentTaskId(String parentTaskId) { this.parentTaskId = parentTaskId; CommandContext commandContext = Context.getCommandContext(); if (commandContext!=null) { commandContext .getHistoryManager() .recordTaskParentTaskIdChange(id, parentTaskId); } } public void setParentTaskIdWithoutCascade(String parentTaskId) { this.parentTaskId = parentTaskId; } public void setTaskDefinitionKeyWithoutCascade(String taskDefinitionKey) { this.taskDefinitionKey = taskDefinitionKey; } public void fireEvent(String taskEventName) { TaskDefinition taskDefinition = getTaskDefinition(); if (taskDefinition != null) { List<TaskListener> taskEventListeners = getTaskDefinition().getTaskListener(taskEventName); if (taskEventListeners != null) { for (TaskListener taskListener : taskEventListeners) { ExecutionEntity execution = getExecution(); if (execution != null) { setEventName(taskEventName); } try { Context.getProcessEngineConfiguration() .getDelegateInterceptor() .handleInvocation(new TaskListenerInvocation(taskListener, (DelegateTask)this)); }catch (Exception e) { throw new ActivitiException("Exception while invoking TaskListener: "+e.getMessage(), e); } } } } } @Override protected boolean isActivityIdUsedForDetails() { return false; } // modified getters and setters ///////////////////////////////////////////// public void setTaskDefinition(TaskDefinition taskDefinition) { this.taskDefinition = taskDefinition; this.taskDefinitionKey = taskDefinition.getKey(); CommandContext commandContext = Context.getCommandContext(); if(commandContext != null) { commandContext.getHistoryManager().recordTaskDefinitionKeyChange(id, taskDefinitionKey); } } public TaskDefinition getTaskDefinition() { if (taskDefinition==null && taskDefinitionKey!=null) { ProcessDefinitionEntity processDefinition = Context .getProcessEngineConfiguration() .getDeploymentCache() .findDeployedProcessDefinitionById(processDefinitionId); taskDefinition = processDefinition.getTaskDefinitions().get(taskDefinitionKey); } return taskDefinition; } // getters and setters ////////////////////////////////////////////////////// public int getRevision() { return revision; } public void setRevision(int revision) { this.revision = revision; } public String getName() { return name; } public String getDescription() { return description; } public Date getDueDate() { return dueDate; } public int getPriority() { return priority; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public String getExecutionId() { return executionId; } public String getProcessInstanceId() { return processInstanceId; } public String getProcessDefinitionId() { return processDefinitionId; } public void setProcessDefinitionId(String processDefinitionId) { this.processDefinitionId = processDefinitionId; } public String getAssignee() { return assignee; } public String getTaskDefinitionKey() { return taskDefinitionKey; } public void setTaskDefinitionKey(String taskDefinitionKey) { this.taskDefinitionKey = taskDefinitionKey; CommandContext commandContext = Context.getCommandContext(); if(commandContext != null) { commandContext.getHistoryManager().recordTaskDefinitionKeyChange(id, taskDefinitionKey); } } public String getEventName() { return eventName; } public void setEventName(String eventName) { this.eventName = eventName; } public void setExecutionId(String executionId) { this.executionId = executionId; } public ExecutionEntity getProcessInstance() { return processInstance; } public void setProcessInstance(ExecutionEntity processInstance) { this.processInstance = processInstance; } public void setExecution(ExecutionEntity execution) { this.execution = execution; } public void setProcessInstanceId(String processInstanceId) { this.processInstanceId = processInstanceId; } public String getOwner() { return owner; } public DelegationState getDelegationState() { return delegationState; } public void setDelegationState(DelegationState delegationState) { this.delegationState = delegationState; } public String getDelegationStateString() { return (delegationState!=null ? delegationState.toString() : null); } public void setDelegationStateString(String delegationStateString) { this.delegationState = (delegationStateString!=null ? DelegationState.valueOf(DelegationState.class, delegationStateString) : null); } public boolean isDeleted() { return isDeleted; } public void setDeleted(boolean isDeleted) { this.isDeleted = isDeleted; } public String getParentTaskId() { return parentTaskId; } public Map<String, VariableInstanceEntity> getVariableInstances() { ensureVariableInstancesInitialized(); return variableInstances; } public int getSuspensionState() { return suspensionState; } public void setSuspensionState(int suspensionState) { this.suspensionState = suspensionState; } public boolean isSuspended() { return suspensionState == SuspensionState.SUSPENDED.getStateCode(); } }