提交 9789e820 编写于 作者: J Joram Barrez

Fix process deletion, consolidating process delete methods in...

Fix process deletion, consolidating process delete methods in ExecutionEntityManager (still needs some love probably)
上级 0b4c4bf3
......@@ -57,54 +57,8 @@ public abstract class AbstractOperation implements Runnable {
execution.setCurrentFlowElement(currentFlowElement);
return currentFlowElement;
}
protected void deleteExecution(CommandContext commandContext, ExecutionEntity executionEntity) {
OperationUtil.deleteDataRelatedToExecution(commandContext, executionEntity);
commandContext.getExecutionEntityManager().delete(executionEntity); // TODO: what about delete reason?
}
protected void deleteProcessInstanceExecutionEntity(CommandContext commandContext, ExecutionEntityManager executionEntityManager, String processInstanceId) {
IdentityLinkEntityManager identityLinkEntityManager = commandContext.getIdentityLinkEntityManager();
List<IdentityLinkEntity> identityLinkEntities = identityLinkEntityManager.findIdentityLinksByProcessInstanceId(processInstanceId);
for (IdentityLinkEntity identityLinkEntity : identityLinkEntities) {
identityLinkEntityManager.delete(identityLinkEntity);
}
ExecutionEntity processInstanceEntity = executionEntityManager.findExecutionById(processInstanceId);
deleteExecution(commandContext, processInstanceEntity);
// TODO: what about delete reason?
Context.getCommandContext().getHistoryManager()
.recordProcessInstanceEnd(processInstanceId, "finished", execution.getCurrentFlowElement() != null ? execution.getCurrentFlowElement().getId() : null);
}
protected void deleteChildExecutions(CommandContext commandContext, ExecutionEntity executionEntity) {
// The children of an execution for a tree. For correct deletions
// (taking care of foreign keys between child-parent)
// the leafs of this tree must be deleted first before the parents
// elements.
// Gather all children
List<ExecutionEntity> childExecutionEntities = new ArrayList<ExecutionEntity>();
LinkedList<ExecutionEntity> uncheckedExecutions = new LinkedList<ExecutionEntity>(executionEntity.getExecutions());
while (!uncheckedExecutions.isEmpty()) {
ExecutionEntity currentExecutionentity = uncheckedExecutions.pop();
childExecutionEntities.add(currentExecutionentity);
uncheckedExecutions.addAll(currentExecutionentity.getExecutions());
}
// Delete them (reverse order : leafs of the tree first)
for (int i = childExecutionEntities.size() - 1; i >= 0; i--) {
ExecutionEntity childExecutionEntity = childExecutionEntities.get(i);
if (childExecutionEntity.isActive() && !childExecutionEntity.isEnded()) {
OperationUtil.deleteDataRelatedToExecution(commandContext, childExecutionEntity);
commandContext.getExecutionEntityManager().delete(childExecutionEntity);
}
}
}
/* TODO: Should following methods be moved to the entityManager */
public CommandContext getCommandContext() {
return commandContext;
......
......@@ -60,7 +60,7 @@ public class DestroyScopeOperation extends AbstractOperation {
// Delete all child executions
Collection<ExecutionEntity> childExecutions = executionEntityManager.findChildExecutionsByParentExecutionId(parentScopeExecution.getId());
for (ExecutionEntity childExcecution : childExecutions) {
deleteExecution(commandContext, childExcecution);
executionEntityManager.deleteExecutionAndRelatedData(childExcecution);
}
// Delete all scope tasks
......
......@@ -43,12 +43,12 @@ public class EndExecutionOperation extends AbstractOperation {
// If the execution is a scope, and it is ended, all the child executions must be deleted first.
if (executionEntity.isScope()) {
deleteChildExecutions(commandContext, executionEntity);
executionEntityManager.deleteChildExecutions(executionEntity);
}
// Delete current execution
logger.debug("Ending execution {}", execution.getId());
deleteExecution(commandContext, executionEntity);
executionEntityManager.deleteExecutionAndRelatedData(executionEntity);
logger.debug("Parent execution found. Continuing process using execution {}", parentExecution.getId());
......@@ -101,7 +101,9 @@ public class EndExecutionOperation extends AbstractOperation {
if (activeExecutions == 0) {
logger.debug("No active executions found. Ending process instance {} ", processInstanceId);
deleteProcessInstanceExecutionEntity(commandContext, executionEntityManager, processInstanceId);
executionEntityManager.deleteProcessInstanceExecutionEntity( processInstanceId,
execution.getCurrentFlowElement() != null ? execution.getCurrentFlowElement().getId() : null,
"FINISHED");
} else {
logger.debug("Active executions found. Process instance {} will not be ended.", processInstanceId);
}
......
/* 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.agenda;
import java.util.Collection;
import java.util.List;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.EventSubscriptionEntity;
import org.activiti.engine.impl.persistence.entity.EventSubscriptionEntityManager;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.JobEntity;
import org.activiti.engine.impl.persistence.entity.JobEntityManager;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntityManager;
import org.activiti.engine.impl.persistence.entity.VariableInstanceEntity;
import org.activiti.engine.impl.persistence.entity.VariableInstanceEntityManager;
public class OperationUtil {
public static void deleteDataRelatedToExecution(CommandContext commandContext, ExecutionEntity executionEntity) {
// To start, deactivate the current incoming execution
executionEntity.setEnded(true);
executionEntity.setActive(false);
// Get variables related to execution and delete them
VariableInstanceEntityManager variableInstanceEntityManager = commandContext.getVariableInstanceEntityManager();
Collection<VariableInstanceEntity> executionVariables = variableInstanceEntityManager.findVariableInstancesByExecutionId(executionEntity.getId());
for (VariableInstanceEntity variableInstanceEntity : executionVariables) {
variableInstanceEntityManager.delete(variableInstanceEntity);
if (variableInstanceEntity.getByteArrayValueId() != null) {
commandContext.getByteArrayEntityManager().deleteByteArrayById(variableInstanceEntity.getByteArrayValueId());
}
}
// Delete current user tasks
TaskEntityManager taskEntityManager = commandContext.getTaskEntityManager();
Collection<TaskEntity> tasksForExecution = taskEntityManager.findTasksByExecutionId(executionEntity.getId());
for (TaskEntity taskEntity : tasksForExecution) {
taskEntityManager.delete(taskEntity);
}
// Delete jobs
JobEntityManager jobEntityManager = commandContext.getJobEntityManager();
Collection<JobEntity> jobsForExecution = jobEntityManager.findJobsByExecutionId(executionEntity.getId());
for (JobEntity job : jobsForExecution) {
jobEntityManager.delete(job);
}
// Delete event subscriptions
EventSubscriptionEntityManager eventSubscriptionEntityManager = Context.getCommandContext().getEventSubscriptionEntityManager();
List<EventSubscriptionEntity> eventSubscriptions = executionEntity.getEventSubscriptions();
for (EventSubscriptionEntity eventSubscription : eventSubscriptions) {
eventSubscriptionEntityManager.deleteEventSubscription(eventSubscription);
}
}
}
......@@ -15,7 +15,6 @@ package org.activiti.engine.impl.bpmn.behavior;
import java.util.Collection;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.impl.agenda.OperationUtil;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
......@@ -145,7 +144,7 @@ public class BoundaryEventActivityBehavior extends FlowNodeActivityBehavior {
}
}
OperationUtil.deleteDataRelatedToExecution(commandContext, parentExecution);
executionEntityManager.deleteDataRelatedToExecution(parentExecution);
commandContext.getExecutionEntityManager().delete(parentExecution);
}
......
......@@ -18,7 +18,6 @@ import java.util.List;
import org.activiti.bpmn.model.Activity;
import org.activiti.engine.ActivitiIllegalArgumentException;
import org.activiti.engine.impl.agenda.OperationUtil;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
......@@ -148,7 +147,7 @@ public class ParallelMultiInstanceBehavior extends MultiInstanceActivityBehavior
}
if (deleteExecution) {
OperationUtil.deleteDataRelatedToExecution(commandContext, parentExecution);
executionEntityManager.deleteDataRelatedToExecution(parentExecution);
commandContext.getExecutionEntityManager().delete(parentExecution);
}
}
......
......@@ -1126,7 +1126,7 @@ public abstract class ProcessEngineConfigurationImpl extends ProcessEngineConfig
List<BpmnParseHandler> parseHandlers = new ArrayList<BpmnParseHandler>();
parseHandlers.add(new FlowNodeHistoryParseHandler());
// parseHandlers.add(new ProcessHistoryParseHandler());
parseHandlers.add(new StartEventHistoryParseHandler());
// parseHandlers.add(new StartEventHistoryParseHandler());
parseHandlers.add(new UserTaskHistoryParseHandler());
return parseHandlers;
}
......
......@@ -48,7 +48,10 @@ public class DeleteProcessInstanceCmd implements Command<Void>, Serializable {
.dispatchEvent(ActivitiEventBuilder.createCancelledEvent(this.processInstanceId, this.processInstanceId, null, deleteReason));
}
commandContext.getExecutionEntityManager().deleteProcessInstance(processInstanceId, deleteReason);
commandContext.getExecutionEntityManager().deleteProcessInstanceExecutionEntity(processInstanceId, null, deleteReason);
// TODO : remove following line of deleteProcessInstanceExecutionEntity is found to be doing the same as deleteProcessInstance
// commandContext.getExecutionEntityManager().deleteProcessInstance(processInstanceId, deleteReason);
return null;
}
......
......@@ -66,12 +66,6 @@ public class StartProcessInstanceCmd<T> implements Command<ProcessInstance>, Ser
public ProcessInstance execute(CommandContext commandContext) {
DeploymentManager deploymentCache = commandContext.getProcessEngineConfiguration().getDeploymentManager();
//
// TODO: Think about cache usage here. How to avoid duplication??
// Probably best to switch to separate caches: one for entities, and one
// for process models.
//
// Find the process definition
ProcessDefinitionEntity processDefinition = null;
if (processDefinitionId != null) {
......
......@@ -134,6 +134,7 @@ public class DefaultHistoryManager extends AbstractManager implements HistoryMan
public void recordProcessInstanceStart(ExecutionEntity processInstance, FlowElement startElement) {
if (isHistoryLevelAtLeast(HistoryLevel.ACTIVITY)) {
HistoricProcessInstanceEntity historicProcessInstance = new HistoricProcessInstanceEntity(processInstance);
historicProcessInstance.setStartActivityId(startElement.getId());
// Insert historic process-instance
getDbSqlSession().insert(historicProcessInstance);
......
......@@ -20,6 +20,8 @@ import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
/**
* @author Tom Baeyens
*
* TODO: Can probably be deleted
*/
public class ProcessInstanceEndHandler implements ExecutionListener {
......
......@@ -20,6 +20,8 @@ import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
/**
* @author Tom Baeyens
*
* TODO: Can probably be deleted
*/
public class StartEventEndHandler implements ExecutionListener {
......
......@@ -20,6 +20,8 @@ import org.activiti.engine.impl.history.handler.ProcessInstanceEndHandler;
/**
* @author Joram Barrez
*
* TODO: can probably be deleted.
*/
public class ProcessHistoryParseHandler extends AbstractBpmnParseHandler<Process> {
......
......@@ -20,6 +20,8 @@ import org.activiti.engine.impl.history.handler.StartEventEndHandler;
/**
* @author Joram Barrez
*
* TODO: can probably be deleted.
*/
public class StartEventHistoryParseHandler extends AbstractBpmnParseHandler<StartEvent> {
......
......@@ -13,12 +13,14 @@
package org.activiti.engine.impl.persistence.entity;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
......@@ -186,6 +188,13 @@ public class ExecutionEntityManager extends AbstractEntityManager<ExecutionEntit
// CREATE METHODS
@Override
public void insert(ExecutionEntity entity, boolean fireCreateEvent) {
super.insert(entity, fireCreateEvent);
}
public ExecutionEntity createProcessInstanceExecution(String processDefinitionId, String businessKey, String tenantId, String initiatorVariableName) {
ExecutionEntity processInstanceExecution = new ExecutionEntity();
......@@ -202,15 +211,16 @@ public class ExecutionEntityManager extends AbstractEntityManager<ExecutionEntit
if (initiatorVariableName != null) {
processInstanceExecution.setVariable(initiatorVariableName, authenticatedUserId);
}
if (authenticatedUserId != null) {
processInstanceExecution.addIdentityLink(authenticatedUserId, null, IdentityLinkType.STARTER);
}
// Store in database
Context.getCommandContext().getExecutionEntityManager().insert(processInstanceExecution);
// Need to be after insert, cause we need the id
processInstanceExecution.setProcessInstanceId(processInstanceExecution.getId());
if (authenticatedUserId != null) {
processInstanceExecution.addIdentityLink(authenticatedUserId, null, IdentityLinkType.STARTER);
}
// Fire events
if (Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
......@@ -252,6 +262,9 @@ public class ExecutionEntityManager extends AbstractEntityManager<ExecutionEntit
}
}
/**
* This method should be deleted in favor of the newer deleteProcessInstanceExecutionEntity method
*/
public void deleteProcessInstance(String processInstanceId, String deleteReason) {
deleteProcessInstance(processInstanceId, deleteReason, false);
}
......@@ -285,6 +298,104 @@ public class ExecutionEntityManager extends AbstractEntityManager<ExecutionEntit
}
}
public void deleteExecutionAndRelatedData(ExecutionEntity executionEntity) {
deleteDataRelatedToExecution(executionEntity);
delete(executionEntity); // TODO: what about delete reason?
}
public void deleteProcessInstanceExecutionEntity(String processInstanceId, String currentFlowElementId, String deleteReason) {
deleteProcessInstanceExecutionEntity(processInstanceId, currentFlowElementId, deleteReason, false);
}
public void deleteProcessInstanceExecutionEntity(String processInstanceId, String currentFlowElementId, String deleteReason, boolean cascade) {
ExecutionEntity processInstanceEntity = findExecutionById(processInstanceId);
for (ExecutionEntity subExecutionEntity : processInstanceEntity.getExecutions()) {
if (subExecutionEntity.getSubProcessInstance() != null) {
deleteProcessInstanceCascade(subExecutionEntity.getSubProcessInstance(), deleteReason, cascade);
}
}
IdentityLinkEntityManager identityLinkEntityManager = Context.getCommandContext().getIdentityLinkEntityManager();
List<IdentityLinkEntity> identityLinkEntities = identityLinkEntityManager.findIdentityLinksByProcessInstanceId(processInstanceId);
for (IdentityLinkEntity identityLinkEntity : identityLinkEntities) {
identityLinkEntityManager.delete(identityLinkEntity);
}
deleteChildExecutions(processInstanceEntity);
deleteExecutionAndRelatedData(processInstanceEntity);
// TODO: what about delete reason?
Context.getCommandContext().getHistoryManager()
.recordProcessInstanceEnd(processInstanceId, deleteReason, currentFlowElementId);
}
public void deleteChildExecutions(ExecutionEntity executionEntity) {
// The children of an execution for a tree. For correct deletions
// (taking care of foreign keys between child-parent)
// the leafs of this tree must be deleted first before the parents elements.
// Gather all children
List<ExecutionEntity> childExecutionEntities = new ArrayList<ExecutionEntity>();
LinkedList<ExecutionEntity> uncheckedExecutions = new LinkedList<ExecutionEntity>(executionEntity.getExecutions());
while (!uncheckedExecutions.isEmpty()) {
ExecutionEntity currentExecutionentity = uncheckedExecutions.pop();
childExecutionEntities.add(currentExecutionentity);
uncheckedExecutions.addAll(currentExecutionentity.getExecutions());
}
// Delete them (reverse order : leafs of the tree first)
for (int i = childExecutionEntities.size() - 1; i >= 0; i--) {
ExecutionEntity childExecutionEntity = childExecutionEntities.get(i);
if (childExecutionEntity.isActive() && !childExecutionEntity.isEnded()) {
deleteExecutionAndRelatedData(childExecutionEntity);
}
}
}
public void deleteDataRelatedToExecution(ExecutionEntity executionEntity) {
// To start, deactivate the current incoming execution
executionEntity.setEnded(true);
executionEntity.setActive(false);
CommandContext commandContext = Context.getCommandContext();
// Get variables related to execution and delete them
VariableInstanceEntityManager variableInstanceEntityManager = commandContext.getVariableInstanceEntityManager();
Collection<VariableInstanceEntity> executionVariables = variableInstanceEntityManager.findVariableInstancesByExecutionId(executionEntity.getId());
for (VariableInstanceEntity variableInstanceEntity : executionVariables) {
variableInstanceEntityManager.delete(variableInstanceEntity);
if (variableInstanceEntity.getByteArrayValueId() != null) {
commandContext.getByteArrayEntityManager().deleteByteArrayById(variableInstanceEntity.getByteArrayValueId());
}
}
// Delete current user tasks
TaskEntityManager taskEntityManager = commandContext.getTaskEntityManager();
Collection<TaskEntity> tasksForExecution = taskEntityManager.findTasksByExecutionId(executionEntity.getId());
for (TaskEntity taskEntity : tasksForExecution) {
taskEntityManager.deleteTask(taskEntity, null, false);
}
// Delete jobs
JobEntityManager jobEntityManager = commandContext.getJobEntityManager();
Collection<JobEntity> jobsForExecution = jobEntityManager.findJobsByExecutionId(executionEntity.getId());
for (JobEntity job : jobsForExecution) {
jobEntityManager.delete(job);
}
// Delete event subscriptions
EventSubscriptionEntityManager eventSubscriptionEntityManager = Context.getCommandContext().getEventSubscriptionEntityManager();
List<EventSubscriptionEntity> eventSubscriptions = executionEntity.getEventSubscriptions();
for (EventSubscriptionEntity eventSubscription : eventSubscriptions) {
eventSubscriptionEntityManager.deleteEventSubscription(eventSubscription);
}
}
// OTHER METHODS
......
......@@ -284,10 +284,12 @@ public abstract class JobEntity implements Job, PersistentObject, HasRevision, B
public void setTenantId(String tenantId) {
this.tenantId = tenantId;
}
public ByteArrayRef getExceptionByteArrayRef() {
return exceptionByteArrayRef;
}
// common methods //////////////////////////////////////////////////////////
@Override
@Override
public String toString() {
return "JobEntity [id=" + id + "]";
}
......
......@@ -55,20 +55,14 @@ public class JobEntityManager extends AbstractEntityManager<JobEntity> {
// pick the job up after the max lock time.
Date dueDate = new Date(processEngineConfiguration.getClock().getCurrentTime().getTime() + processEngineConfiguration.getAsyncExecutor().getAsyncJobLockTimeInMillis());
message.setDuedate(dueDate);
message.setLockExpirationTime(null); // was set before, but to be
// quickly picked up needs to
// be set to null
message.setLockExpirationTime(null); // was set before, but to be quickly picked up needs to be set to null
} else if (!processEngineConfiguration.isJobExecutorActivate()) {
// If the async executor is disabled AND there is no old school job
// executor,
// The job needs to be picked up as soon as possible. So the due
// date is now set to the current time
// executor, The job needs to be picked up as soon as possible. So the due date is now set to the current time
message.setDuedate(processEngineConfiguration.getClock().getCurrentTime());
message.setLockExpirationTime(null); // was set before, but to be
// quickly picked up needs to
// be set to null
message.setLockExpirationTime(null); // was set before, but to be quickly picked up needs to be set to null
}
message.insert();
......@@ -212,5 +206,21 @@ public class JobEntityManager extends AbstractEntityManager<JobEntity> {
params.put("dueDate", Context.getProcessEngineConfiguration().getClock().getCurrentTime());
return getDbSqlSession().update("updateJobLockForAllJobs", params);
}
@Override
public void delete(JobEntity jobEntity) {
super.delete(jobEntity);
ByteArrayRef exceptionByteArrayRef = jobEntity.getExceptionByteArrayRef();
// Also delete the job's exception byte array
exceptionByteArrayRef.delete();
// remove link to execution
if (jobEntity.getExecutionId() != null) {
ExecutionEntity execution = Context.getCommandContext().getExecutionEntityManager().findExecutionById(jobEntity.getExecutionId());
execution.removeJob(jobEntity);
}
}
}
......@@ -127,8 +127,7 @@ public class AsyncTaskTest extends PluggableActivitiTestCase {
assertEquals("service", runtimeService.getActiveActivityIds(execution.getId()).get(0));
// there is still a single job because the timer was created in the same
// transaction as the
// service was executed (which rolled back)
// transaction as the service was executed (which rolled back)
assertEquals(1, managementService.createJobQuery().count());
runtimeService.deleteProcessInstance(execution.getId(), "dead");
......
......@@ -34,16 +34,12 @@ public class TaskListenerTest extends PluggableActivitiTestCase {
// Manually cleanup the process instance. If we don't do this, the
// following actions will occur:
// 1. The cleanup rule will delete the process
// 2. The process deletion will fire a DELETE event to the
// TaskAllEventsListener
// 2. The process deletion will fire a DELETE event to the TaskAllEventsListener
// 3. The TaskAllEventsListener will set a variable on the Task
// 4. Setting that variable will result in an entry in the ACT_HI_DETAIL
// table
// 5. The AbstractActivitiTestCase will fail the test because the DB is
// not clean
// 4. Setting that variable will result in an entry in the ACT_HI_DETAIL table
// 5. The AbstractActivitiTestCase will fail the test because the DB is not clean
// By triggering the DELETE event from within the test, we ensure that
// all of the records
// are written before the test cleanup begins
// all of the records are written before the test cleanup begins
runtimeService.deleteProcessInstance(processInstance.getProcessInstanceId(), "");
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册