Skip to content

Commit

Permalink
feat(engine): add historicProcInsQuery to executeModificationAsync
Browse files Browse the repository at this point in the history
related to: camunda#4620
  • Loading branch information
venetrius authored Sep 20, 2024
1 parent 79b001b commit 1b9de30
Show file tree
Hide file tree
Showing 10 changed files with 627 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@
desc = "A process instance query."
/>

<@lib.property
name = "historicProcessInstanceQuery"
type = "ref"
dto = "HistoricProcessInstanceQueryDto"
desc = "A historic process instance query. It is advised to include the `unfinished` filter in the
historic process instance query as finished instances cause failures for the modification."
/>

<@lib.property
name = "instructions"
type = "array"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import java.util.List;

import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.history.HistoricProcessInstanceQuery;
import org.camunda.bpm.engine.rest.dto.history.HistoricProcessInstanceQueryDto;
import org.camunda.bpm.engine.rest.dto.runtime.ProcessInstanceQueryDto;
import org.camunda.bpm.engine.rest.dto.runtime.modification.ProcessInstanceModificationInstructionDto;
import org.camunda.bpm.engine.runtime.ModificationBuilder;
Expand All @@ -30,6 +32,7 @@ public class ModificationDto {
protected List<ProcessInstanceModificationInstructionDto> instructions;
protected List<String> processInstanceIds;
protected ProcessInstanceQueryDto processInstanceQuery;
protected HistoricProcessInstanceQueryDto historicProcessInstanceQuery;
protected String processDefinitionId;
protected boolean skipIoMappings;
protected boolean skipCustomListeners;
Expand Down Expand Up @@ -99,4 +102,11 @@ public void setAnnotation(String annotation) {
this.annotation = annotation;
}

public HistoricProcessInstanceQueryDto getHistoricProcessInstanceQuery() {
return historicProcessInstanceQuery;
}

public void setHistoricProcessInstanceQuery(HistoricProcessInstanceQueryDto historicProcessInstanceQuery) {
this.historicProcessInstanceQuery = historicProcessInstanceQuery;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@

import org.camunda.bpm.engine.BadUserRequestException;
import org.camunda.bpm.engine.batch.Batch;
import org.camunda.bpm.engine.history.HistoricProcessInstanceQuery;
import org.camunda.bpm.engine.rest.ModificationRestService;
import org.camunda.bpm.engine.rest.dto.ModificationDto;
import org.camunda.bpm.engine.rest.dto.batch.BatchDto;
import org.camunda.bpm.engine.rest.dto.history.HistoricProcessInstanceQueryDto;
import org.camunda.bpm.engine.rest.dto.runtime.ProcessInstanceQueryDto;
import org.camunda.bpm.engine.rest.exception.InvalidRequestException;
import org.camunda.bpm.engine.runtime.ModificationBuilder;
Expand Down Expand Up @@ -74,6 +76,12 @@ private ModificationBuilder createModificationBuilder(ModificationDto dto) {
builder.processInstanceQuery(processInstanceQuery);
}

HistoricProcessInstanceQueryDto historicProcessInstanceQueryDto = dto.getHistoricProcessInstanceQuery();
if(historicProcessInstanceQueryDto != null) {
HistoricProcessInstanceQuery historicProcessInstanceQuery = historicProcessInstanceQueryDto.toQuery(getProcessEngine());
builder.historicProcessInstanceQuery(historicProcessInstanceQuery);
}

if (dto.isSkipCustomListeners()) {
builder.skipCustomListeners();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@

import org.camunda.bpm.engine.AuthorizationException;
import org.camunda.bpm.engine.BadUserRequestException;
import org.camunda.bpm.engine.HistoryService;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.batch.Batch;
import org.camunda.bpm.engine.impl.HistoricProcessInstanceQueryImpl;
import org.camunda.bpm.engine.impl.ProcessInstanceQueryImpl;
import org.camunda.bpm.engine.rest.dto.history.HistoricProcessInstanceQueryDto;
import org.camunda.bpm.engine.rest.dto.runtime.ProcessInstanceQueryDto;
import org.camunda.bpm.engine.rest.exception.InvalidRequestException;
import org.camunda.bpm.engine.rest.util.ModificationInstructionBuilder;
Expand All @@ -57,13 +60,17 @@ public class ModificationRestServiceInteractionTest extends AbstractRestServiceT
protected static final String EXECUTE_MODIFICATION_ASYNC_URL = PROCESS_INSTANCE_URL + "/executeAsync";

protected RuntimeService runtimeServiceMock;
protected HistoryService historyServiceMock;
protected ModificationBuilder modificationBuilderMock;

@Before
public void setUpRuntimeData() {
runtimeServiceMock = mock(RuntimeService.class);
when(processEngine.getRuntimeService()).thenReturn(runtimeServiceMock);

historyServiceMock = mock(HistoryService.class);
when(processEngine.getHistoryService()).thenReturn(historyServiceMock);

modificationBuilderMock = mock(ModificationBuilder.class);
when(modificationBuilderMock.cancelAllForActivity(any())).thenReturn(modificationBuilderMock);
when(modificationBuilderMock.startAfterActivity(any())).thenReturn(modificationBuilderMock);
Expand Down Expand Up @@ -299,6 +306,39 @@ public void executeModificationWithValidProcessInstanceQuerySync() {
verify(modificationBuilderMock).execute();
}

@Test
public void executeModificationWithValidHistoricProcessInstanceQuerySync() {

when(historyServiceMock.createHistoricProcessInstanceQuery()).thenReturn(new HistoricProcessInstanceQueryImpl());
Map<String, Object> json = new HashMap<String, Object>();

List<Map<String, Object>> instructions = new ArrayList<Map<String, Object>>();
instructions.add(ModificationInstructionBuilder.startAfter().activityId("activityId").getJson());
json.put("processDefinitionId", "processDefinitionId");

HistoricProcessInstanceQueryDto historicProcessInstanceQueryDto = new HistoricProcessInstanceQueryDto();
historicProcessInstanceQueryDto.setProcessInstanceBusinessKey("foo");

json.put("historicProcessInstanceQuery", historicProcessInstanceQueryDto);

json.put("instructions", instructions);

given()
.contentType(ContentType.JSON)
.body(json)
.then()
.expect()
.statusCode(Status.NO_CONTENT.getStatusCode())
.when()
.post(EXECUTE_MODIFICATION_SYNC_URL);

verify(historyServiceMock, times(1)).createHistoricProcessInstanceQuery();
verify(modificationBuilderMock).startAfterActivity("activityId");
verify(modificationBuilderMock).historicProcessInstanceQuery(historicProcessInstanceQueryDto.toQuery(processEngine));
verify(modificationBuilderMock).execute();
}


@Test
public void executeModificationWithValidProcessInstanceQueryAsync() {

Expand Down Expand Up @@ -330,6 +370,74 @@ public void executeModificationWithValidProcessInstanceQueryAsync() {
verify(modificationBuilderMock).executeAsync();
}

@Test
public void executeModificationWithValidHistoricProcessInstanceQueryAsync() {
when(historyServiceMock.createHistoricProcessInstanceQuery()).thenReturn(new HistoricProcessInstanceQueryImpl());
Map<String, Object> json = new HashMap<String, Object>();

List<Map<String, Object>> instructions = new ArrayList<Map<String, Object>>();
instructions.add(ModificationInstructionBuilder.startAfter().activityId("activityId").getJson());

HistoricProcessInstanceQueryDto historicProcessInstanceQueryDto = new HistoricProcessInstanceQueryDto();
historicProcessInstanceQueryDto.setProcessInstanceBusinessKey("foo");

json.put("historicProcessInstanceQuery", historicProcessInstanceQueryDto);
json.put("instructions", instructions);
json.put("processDefinitionId", "processDefinitionId");

given()
.contentType(ContentType.JSON)
.body(json)
.then()
.expect()
.statusCode(Status.OK.getStatusCode())
.when()
.post(EXECUTE_MODIFICATION_ASYNC_URL);

verify(historyServiceMock, times(1)).createHistoricProcessInstanceQuery();
verify(modificationBuilderMock).startAfterActivity("activityId");
verify(modificationBuilderMock).historicProcessInstanceQuery(historicProcessInstanceQueryDto.toQuery(processEngine));
verify(modificationBuilderMock).executeAsync();
}

@Test
public void executeModificationWithBothProcessInstanceQueries() {
when(historyServiceMock.createHistoricProcessInstanceQuery()).thenReturn(new HistoricProcessInstanceQueryImpl());
when(runtimeServiceMock.createProcessInstanceQuery()).thenReturn(new ProcessInstanceQueryImpl());

Map<String, Object> json = new HashMap<String, Object>();

List<Map<String, Object>> instructions = new ArrayList<Map<String, Object>>();
instructions.add(ModificationInstructionBuilder.startAfter().activityId("activityId").getJson());

HistoricProcessInstanceQueryDto historicProcessInstanceQueryDto = new HistoricProcessInstanceQueryDto();
historicProcessInstanceQueryDto.setProcessInstanceBusinessKey("foo");

ProcessInstanceQueryDto processInstanceQueryDto = new ProcessInstanceQueryDto();
processInstanceQueryDto.setBusinessKey("foo");

json.put("processInstanceQuery", processInstanceQueryDto);
json.put("historicProcessInstanceQuery", historicProcessInstanceQueryDto);
json.put("instructions", instructions);
json.put("processDefinitionId", "processDefinitionId");

given()
.contentType(ContentType.JSON)
.body(json)
.then()
.expect()
.statusCode(Status.OK.getStatusCode())
.when()
.post(EXECUTE_MODIFICATION_ASYNC_URL);

verify(historyServiceMock, times(1)).createHistoricProcessInstanceQuery();
verify(modificationBuilderMock).startAfterActivity("activityId");
verify(modificationBuilderMock).historicProcessInstanceQuery(historicProcessInstanceQueryDto.toQuery(processEngine));
verify(runtimeServiceMock, times(1)).createProcessInstanceQuery();
verify(modificationBuilderMock).processInstanceQuery(processInstanceQueryDto.toQuery(processEngine));
verify(modificationBuilderMock).executeAsync();
}

@Test
public void executeModificationWithInvalidProcessInstanceQuerySync() {

Expand Down Expand Up @@ -359,6 +467,35 @@ public void executeModificationWithInvalidProcessInstanceQuerySync() {

}

@Test
public void executeModificationWithInvalidHistoricProcessInstanceQuerySync() {
when(historyServiceMock.createHistoricProcessInstanceQuery()).thenReturn(new HistoricProcessInstanceQueryImpl());

Map<String, Object> json = new HashMap<String, Object>();

String message = "Process instance ids is null";
doThrow(new BadUserRequestException(message)).when(modificationBuilderMock).execute();

List<Map<String, Object>> instructions = new ArrayList<Map<String, Object>>();
instructions.add(ModificationInstructionBuilder.startAfter().activityId("acivityId").getJson());

HistoricProcessInstanceQueryDto historicProcessInstanceQueryDto = new HistoricProcessInstanceQueryDto();
historicProcessInstanceQueryDto.setProcessInstanceBusinessKey("foo");

json.put("historicProcessInstanceQuery", historicProcessInstanceQueryDto);
json.put("instructions", instructions);
json.put("processDefinitionId", "processDefinitionId");

given()
.contentType(ContentType.JSON)
.body(json)
.then()
.expect()
.statusCode(Status.BAD_REQUEST.getStatusCode())
.when()
.post(EXECUTE_MODIFICATION_SYNC_URL);
}

@Test
public void executeModificationWithInvalidProcessInstanceQueryAsync() {

Expand All @@ -384,6 +521,31 @@ public void executeModificationWithInvalidProcessInstanceQueryAsync() {
.post(EXECUTE_MODIFICATION_ASYNC_URL);
}

@Test
public void executeModificationWithInvalidHistoricProcessInstanceQueryAsync() {
when(historyServiceMock.createHistoricProcessInstanceQuery()).thenReturn(new HistoricProcessInstanceQueryImpl());
Map<String, Object> json = new HashMap<String, Object>();

List<Map<String, Object>> instructions = new ArrayList<Map<String, Object>>();
instructions.add(ModificationInstructionBuilder.startAfter().activityId("acivityId").getJson());

HistoricProcessInstanceQueryDto historicProcessInstanceQueryDto = new HistoricProcessInstanceQueryDto();
historicProcessInstanceQueryDto.setProcessInstanceBusinessKey("foo");

json.put("historicProcessInstanceQuery", historicProcessInstanceQueryDto);
json.put("instructions", instructions);
json.put("processDefinitionId", "processDefinitionId");

given()
.contentType(ContentType.JSON)
.body(json)
.then()
.expect()
.statusCode(Status.OK.getStatusCode())
.when()
.post(EXECUTE_MODIFICATION_ASYNC_URL);
}

@Test
public void executeModificationWithNullInstructionsSync() {
doThrow(new BadUserRequestException("Instructions must be set")).when(modificationBuilderMock).execute();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import org.camunda.bpm.engine.batch.Batch;
import org.camunda.bpm.engine.exception.NotValidException;
import org.camunda.bpm.engine.history.HistoricProcessInstanceQuery;
import org.camunda.bpm.engine.impl.cmd.AbstractProcessInstanceModificationCommand;
import org.camunda.bpm.engine.impl.cmd.ActivityAfterInstantiationCmd;
import org.camunda.bpm.engine.impl.cmd.ActivityBeforeInstantiationCmd;
Expand All @@ -40,6 +41,7 @@ public class ModificationBuilderImpl implements ModificationBuilder {

protected CommandExecutor commandExecutor;
protected ProcessInstanceQuery processInstanceQuery;
protected HistoricProcessInstanceQuery historicProcessInstanceQuery;
protected List<String> processInstanceIds;
protected List<AbstractProcessInstanceModificationCommand> instructions;
protected String processDefinitionId;
Expand Down Expand Up @@ -114,6 +116,12 @@ public ModificationBuilder processInstanceQuery(ProcessInstanceQuery processInst
return this;
}

@Override
public ModificationBuilder historicProcessInstanceQuery(HistoricProcessInstanceQuery historicProcessInstanceQuery) {
this.historicProcessInstanceQuery = historicProcessInstanceQuery;
return this;
}

@Override
public ModificationBuilder skipCustomListeners() {
this.skipCustomListeners = true;
Expand Down Expand Up @@ -153,6 +161,10 @@ public ProcessInstanceQuery getProcessInstanceQuery() {
return processInstanceQuery;
}

public HistoricProcessInstanceQuery getHistoricProcessInstanceQuery() {
return historicProcessInstanceQuery;
}

public List<String> getProcessInstanceIds() {
return processInstanceIds;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Set;

import org.camunda.bpm.engine.history.UserOperationLogEntry;
import org.camunda.bpm.engine.impl.HistoricProcessInstanceQueryImpl;
import org.camunda.bpm.engine.impl.ModificationBuilderImpl;
import org.camunda.bpm.engine.impl.ProcessInstanceQueryImpl;
import org.camunda.bpm.engine.impl.interceptor.Command;
Expand Down Expand Up @@ -53,6 +54,12 @@ protected Collection<String> collectProcessInstanceIds() {
collectedProcessInstanceIds.addAll(processInstanceQuery.listIds());
}

final HistoricProcessInstanceQueryImpl historicProcessInstanceQuery =
(HistoricProcessInstanceQueryImpl) builder.getHistoricProcessInstanceQuery();
if(historicProcessInstanceQuery != null) {
collectedProcessInstanceIds.addAll(historicProcessInstanceQuery.listIds());
}

return collectedProcessInstanceIds;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.camunda.bpm.engine.authorization.Permissions;
import org.camunda.bpm.engine.authorization.Resources;
import org.camunda.bpm.engine.batch.Batch;
import org.camunda.bpm.engine.history.HistoricProcessInstanceQuery;

public interface ModificationBuilder extends InstantiationBuilder<ModificationBuilder>{

Expand Down Expand Up @@ -116,5 +117,12 @@ public interface ModificationBuilder extends InstantiationBuilder<ModificationBu
* </ul>
*/
Batch executeAsync();

/**
* @param historicProcessInstanceQuery a query which selects the process instances to modify.
* It is advised to include the `unfinished` filter in the historicProcessInstanceQuery as finished instances cause failures for the modification.
* Query results are restricted to process instances for which the user has {@link Permissions#READ_HISTORY} permission.
*/
ModificationBuilder historicProcessInstanceQuery(HistoricProcessInstanceQuery historicProcessInstanceQuery);
}

Loading

0 comments on commit 1b9de30

Please sign in to comment.