Skip to content

Commit

Permalink
fix(set/version): update historic process instance
Browse files Browse the repository at this point in the history
related to CAM-4375
  • Loading branch information
ingorichtsmeier authored and romansmirnov committed Aug 13, 2015
1 parent 8e38610 commit d06a24e
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,23 @@

import org.camunda.bpm.engine.ProcessEngineException;
import org.camunda.bpm.engine.history.HistoricProcessInstance;
import org.camunda.bpm.engine.impl.context.Context;
import org.camunda.bpm.engine.history.UserOperationLogEntry;
import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.camunda.bpm.engine.impl.history.HistoryLevel;
import org.camunda.bpm.engine.impl.history.event.HistoryEvent;
import org.camunda.bpm.engine.impl.history.event.HistoryEventTypes;
import org.camunda.bpm.engine.impl.history.handler.HistoryEventHandler;
import org.camunda.bpm.engine.impl.history.producer.HistoryEventProducer;
import org.camunda.bpm.engine.impl.interceptor.Command;
import org.camunda.bpm.engine.impl.interceptor.CommandContext;
import org.camunda.bpm.engine.impl.persistence.deploy.DeploymentCache;
import org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity;
import org.camunda.bpm.engine.impl.persistence.entity.ExecutionManager;
import org.camunda.bpm.engine.impl.persistence.entity.HistoricProcessInstanceEntity;
import org.camunda.bpm.engine.impl.persistence.entity.HistoricProcessInstanceManager;
import org.camunda.bpm.engine.impl.persistence.entity.IncidentEntity;
import org.camunda.bpm.engine.impl.persistence.entity.JobDefinitionEntity;
import org.camunda.bpm.engine.impl.persistence.entity.JobEntity;
import org.camunda.bpm.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.camunda.bpm.engine.impl.persistence.entity.PropertyChange;
import org.camunda.bpm.engine.impl.persistence.entity.TaskEntity;
import org.camunda.bpm.engine.impl.pvm.PvmActivity;
import org.camunda.bpm.engine.impl.pvm.process.ProcessDefinitionImpl;
Expand Down Expand Up @@ -66,6 +71,7 @@
*
* @see http://forums.activiti.org/en/viewtopic.php?t=2918
* @author Falko Menge
* @author Ingo Richtsmeier
*/
public class SetProcessDefinitionVersionCmd implements Command<Void>, Serializable {

Expand All @@ -83,6 +89,8 @@ public SetProcessDefinitionVersionCmd(String processInstanceId, Integer processD
}

public Void execute(CommandContext commandContext) {
ProcessEngineConfigurationImpl configuration = commandContext.getProcessEngineConfiguration();

// check that the new process definition is just another version of the same
// process definition that the process instance is using
ExecutionManager executionManager = commandContext.getExecutionManager();
Expand All @@ -99,9 +107,7 @@ public Void execute(CommandContext commandContext) {
}
ProcessDefinitionImpl currentProcessDefinitionImpl = processInstance.getProcessDefinition();

DeploymentCache deploymentCache = Context
.getProcessEngineConfiguration()
.getDeploymentCache();
DeploymentCache deploymentCache = configuration.getDeploymentCache();
ProcessDefinitionEntity currentProcessDefinition;
if (currentProcessDefinitionImpl instanceof ProcessDefinitionEntity) {
currentProcessDefinition = (ProcessDefinitionEntity) currentProcessDefinitionImpl;
Expand All @@ -114,11 +120,14 @@ public Void execute(CommandContext commandContext) {

validateAndSwitchVersionOfExecution(commandContext, processInstance, newProcessDefinition);

// switch the historic process instance to the new process definition version
HistoricProcessInstanceManager historicProcessInstanceManager = commandContext.getHistoricProcessInstanceManager();
if (historicProcessInstanceManager.isHistoryEnabled()) {
HistoricProcessInstanceEntity historicProcessInstance = historicProcessInstanceManager.findHistoricProcessInstance(processInstanceId);
historicProcessInstance.setProcessDefinitionId(newProcessDefinition.getId());
HistoryLevel historyLevel = configuration.getHistoryLevel();
if(historyLevel.isHistoryEventProduced(HistoryEventTypes.PROCESS_INSTANCE_UPDATE, processInstance)) {
HistoryEventProducer eventFactory = configuration.getHistoryEventProducer();
HistoryEventHandler eventHandler = configuration.getHistoryEventHandler();

// publish event for historic process instance
HistoryEvent event = eventFactory.createProcessInstanceUpdateEvt(processInstance);
eventHandler.handleEvent(event);
}

// switch all sub-executions of the process instance to the new process definition version
Expand Down Expand Up @@ -146,6 +155,10 @@ public Void execute(CommandContext commandContext) {
switchVersionOfIncident(commandContext, incidentEntity, newProcessDefinition);
}

// add an entry to the op log
PropertyChange change = new PropertyChange("processDefinitionVersion", currentProcessDefinition.getVersion(), processDefinitionVersion);
commandContext.getOperationLogManager().logProcessInstanceOperation(UserOperationLogEntry.OPERATION_TYPE_MODIFY_PROCESS_INSTANCE, processInstanceId, null, null, change);

return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import static org.camunda.bpm.engine.impl.history.event.HistoryEventTypes.CASE_INSTANCE_UPDATE;
import static org.camunda.bpm.engine.impl.history.event.HistoryEventTypes.PROCESS_INSTANCE_END;
import static org.camunda.bpm.engine.impl.history.event.HistoryEventTypes.PROCESS_INSTANCE_START;
import static org.camunda.bpm.engine.impl.history.event.HistoryEventTypes.PROCESS_INSTANCE_UPDATE;
import static org.camunda.bpm.engine.impl.history.event.HistoryEventTypes.TASK_INSTANCE_COMPLETE;
import static org.camunda.bpm.engine.impl.history.event.HistoryEventTypes.TASK_INSTANCE_CREATE;
import static org.camunda.bpm.engine.impl.history.event.HistoryEventTypes.TASK_INSTANCE_DELETE;
Expand All @@ -47,6 +48,7 @@ public String getName() {

public boolean isHistoryEventProduced(HistoryEventType eventType, Object entity) {
return PROCESS_INSTANCE_START == eventType
|| PROCESS_INSTANCE_UPDATE == eventType
|| PROCESS_INSTANCE_END == eventType

|| TASK_INSTANCE_CREATE == eventType
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@
* The set of built-in history event types.
*
* @author Daniel Meyer
* @author Ingo Richtsmeier
* @since 7.2
*/
public enum HistoryEventTypes implements HistoryEventType {

/** fired when a process instance is started. */
PROCESS_INSTANCE_START("process-instance", "start"),
/** fired when a process instance is updated */
PROCESS_INSTANCE_UPDATE("process-instance-update", "update"),
/** fired when a process instance is ended. */
PROCESS_INSTANCE_END("process-instance", "end"),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.DelegateTask;
Expand Down Expand Up @@ -53,16 +52,15 @@
import org.camunda.bpm.engine.impl.persistence.entity.TaskEntity;
import org.camunda.bpm.engine.impl.persistence.entity.VariableInstanceEntity;
import org.camunda.bpm.engine.impl.pvm.PvmScope;
import org.camunda.bpm.engine.impl.pvm.process.ScopeImpl;
import org.camunda.bpm.engine.impl.pvm.runtime.CompensationBehavior;
import org.camunda.bpm.engine.impl.pvm.runtime.PvmExecutionImpl;
import org.camunda.bpm.engine.impl.util.ClockUtil;
import org.camunda.bpm.engine.management.JobDefinition;
import org.camunda.bpm.engine.runtime.Incident;
import org.camunda.bpm.engine.runtime.Job;

/**
* @author Daniel Meyer
* @author Ingo Richtsmeier
*
*/
public class DefaultHistoryEventProducer implements HistoryEventProducer {
Expand Down Expand Up @@ -412,6 +410,18 @@ public HistoryEvent createProcessInstanceStartEvt(DelegateExecution execution) {
return evt;
}

public HistoryEvent createProcessInstanceUpdateEvt(DelegateExecution execution) {
final ExecutionEntity executionEntity = (ExecutionEntity) execution;

// create event instance
HistoricProcessInstanceEventEntity evt = newProcessInstanceEventEntity(executionEntity);

// initialize event
initProcessInstanceEvent(evt, executionEntity, HistoryEventTypes.PROCESS_INSTANCE_UPDATE);

return evt;
}

public HistoryEvent createProcessInstanceEndEvt(DelegateExecution execution) {
final ExecutionEntity executionEntity = (ExecutionEntity) execution;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
*
* @author Daniel Meyer
* @author Marcel Wieczorek
* @author Ingo Richtsmeier
*
*/
public interface HistoryEventProducer {
Expand All @@ -45,6 +46,14 @@ public interface HistoryEventProducer {
*/
public HistoryEvent createProcessInstanceStartEvt(DelegateExecution execution);

/**
* Creates the history event fired when a process instance is <strong>updated</strong>.
*
* @param processExecution the current case execution
* @return the created history event
*/
public HistoryEvent createProcessInstanceUpdateEvt(DelegateExecution execution);

/**
* Creates the history event fired when a process instances is <strong>ended</strong>.
*
Expand All @@ -53,7 +62,6 @@ public interface HistoryEventProducer {
*/
public HistoryEvent createProcessInstanceEndEvt(DelegateExecution execution);


// Activity instances /////////////////////////////////////

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@

import org.camunda.bpm.engine.ProcessEngineException;
import org.camunda.bpm.engine.history.HistoricProcessInstance;
import org.camunda.bpm.engine.history.UserOperationLogEntry;
import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.camunda.bpm.engine.impl.cmd.SetProcessDefinitionVersionCmd;
import org.camunda.bpm.engine.impl.history.HistoryLevel;
import org.camunda.bpm.engine.impl.interceptor.CommandExecutor;
import org.camunda.bpm.engine.impl.jobexecutor.MessageJobDeclaration;
import org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity;
Expand Down Expand Up @@ -54,7 +56,7 @@ public class ProcessInstanceMigrationTest extends PluggableProcessEngineTestCase

private static final String TEST_PROCESS_ONE_JOB = "org/camunda/bpm/engine/test/db/ProcessInstanceMigrationTest.oneJobProcess.bpmn20.xml";
private static final String TEST_PROCESS_TWO_JOBS = "org/camunda/bpm/engine/test/db/ProcessInstanceMigrationTest.twoJobsProcess.bpmn20.xml";

private static final String TEST_PROCESS_ATTACHED_TIMER = "org/camunda/bpm/engine/test/db/ProcessInstanceMigrationTest.testAttachedTimer.bpmn20.xml";

public void testSetProcessDefinitionVersionEmptyArguments() {
Expand Down Expand Up @@ -528,7 +530,7 @@ public void testSetProcessDefinitionVersionMigrateIncident() {

repositoryService.deleteDeployment(deployment.getId(), true);
}

@Deployment(resources = TEST_PROCESS_ATTACHED_TIMER)
public void testSetProcessDefinitionVersionAttachedTimer() {
// given a process instance
Expand All @@ -555,4 +557,120 @@ public void testSetProcessDefinitionVersionAttachedTimer() {

repositoryService.deleteDeployment(deployment.getId(), true);
}

public void testHistoryOfSetProcessDefinitionVersionCmd() {
// given
String resource = "org/camunda/bpm/engine/test/db/SetProcessDefinitionVersionCmdTest.bpmn";

// Deployments
org.camunda.bpm.engine.repository.Deployment firstDeployment = repositoryService
.createDeployment()
.addClasspathResource(resource)
.deploy();

org.camunda.bpm.engine.repository.Deployment secondDeployment = repositoryService
.createDeployment()
.addClasspathResource(resource)
.deploy();

// Process definitions
ProcessDefinition processDefinitionV1 = repositoryService
.createProcessDefinitionQuery()
.deploymentId(firstDeployment.getId())
.singleResult();

ProcessDefinition processDefinitionV2 = repositoryService
.createProcessDefinitionQuery()
.deploymentId(secondDeployment.getId())
.singleResult();

// start process instance
ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionV1.getId());

// when
setProcessDefinitionVersion(processInstance.getId(), 2);

// then
ProcessInstance processInstanceAfterMigration = runtimeService
.createProcessInstanceQuery()
.processInstanceId(processInstance.getId())
.singleResult();
assertEquals(processDefinitionV2.getId(), processInstanceAfterMigration.getProcessDefinitionId());

if(processEngineConfiguration.getHistoryLevel().getId() > ProcessEngineConfigurationImpl.HISTORYLEVEL_NONE) {
HistoricProcessInstance historicProcessInstance = historyService
.createHistoricProcessInstanceQuery()
.processInstanceId(processInstance.getId())
.singleResult();
assertEquals(processDefinitionV2.getId(), historicProcessInstance.getProcessDefinitionId());
}

// Clean up the test
repositoryService.deleteDeployment(firstDeployment.getId(), true);
repositoryService.deleteDeployment(secondDeployment.getId(), true);
}

public void testOpLogSetProcessDefinitionVersionCmd() {
// given
String resource = "org/camunda/bpm/engine/test/db/SetProcessDefinitionVersionCmdTest.bpmn";

// Deployments
org.camunda.bpm.engine.repository.Deployment firstDeployment = repositoryService
.createDeployment()
.addClasspathResource(resource)
.deploy();

org.camunda.bpm.engine.repository.Deployment secondDeployment = repositoryService
.createDeployment()
.addClasspathResource(resource)
.deploy();

// Process definitions
ProcessDefinition processDefinitionV1 = repositoryService
.createProcessDefinitionQuery()
.deploymentId(firstDeployment.getId())
.singleResult();

ProcessDefinition processDefinitionV2 = repositoryService
.createProcessDefinitionQuery()
.deploymentId(secondDeployment.getId())
.singleResult();

// start process instance
ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionV1.getId());

// when
setProcessDefinitionVersion(processInstance.getId(), 2);

// then
ProcessInstance processInstanceAfterMigration = runtimeService
.createProcessInstanceQuery()
.processInstanceId(processInstance.getId())
.singleResult();
assertEquals(processDefinitionV2.getId(), processInstanceAfterMigration.getProcessDefinitionId());

if (processEngineConfiguration.getHistoryLevel().equals(HistoryLevel.HISTORY_LEVEL_FULL)) {
List<UserOperationLogEntry> userOperations = historyService
.createUserOperationLogQuery()
.processInstanceId(processInstance.getId())
.list();

assertEquals(1, userOperations.size());

UserOperationLogEntry userOperationLogEntry = userOperations.get(0);
assertEquals(UserOperationLogEntry.OPERATION_TYPE_MODIFY_PROCESS_INSTANCE, userOperationLogEntry.getOperationType());
assertEquals("processDefinitionVersion", userOperationLogEntry.getProperty());
assertEquals("1", userOperationLogEntry.getOrgValue());
assertEquals("2", userOperationLogEntry.getNewValue());
}

// Clean up the test
repositoryService.deleteDeployment(firstDeployment.getId(), true);
repositoryService.deleteDeployment(secondDeployment.getId(), true);
}

protected void setProcessDefinitionVersion(String processInstanceId, int newProcessDefinitionVersion) {
CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutorTxRequiresNew();
commandExecutor.execute(new SetProcessDefinitionVersionCmd(processInstanceId, newProcessDefinitionVersion));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions id="definitions"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
targetNamespace="Examples">

<process id="SetProcessDefinitionVersionCmdTest" isExecutable="true">

<startEvent id="theStart" />

<sequenceFlow sourceRef="theStart" targetRef="theTask" />

<userTask id="theTask" />

<sequenceFlow sourceRef="theTask" targetRef="theEnd" />

<endEvent id="theEnd" />

</process>

</definitions>

0 comments on commit d06a24e

Please sign in to comment.