@ApiOperation(value = "Complete an External Worker Job with a cmmn terminate transition", code = 204, tags = { "Acquire and Execute" })
    @ApiResponses({
            @ApiResponse(code = 204, message = "Indicates the job was successfully transitioned."),
            @ApiResponse(code = 400, message = "Indicates the request was invalid."),
            @ApiResponse(code = 403, message = "Indicates the user does not have the rights complete the job."),
            @ApiResponse(code = 404, message = "Indicates the job does not exist."),
    })
    @PostMapping(value = "/acquire/jobs/{jobId}/cmmnTerminate", produces = "application/json")
    public ResponseEntity<?> terminateCmmnJob(@PathVariable String jobId, @RequestBody ExternalWorkerJobTerminateRequest request) {
        String workerId = request.getWorkerId();
        if (StringUtils.isEmpty(workerId)) {
            throw new FlowableIllegalArgumentException("workerId is required");
        }

        ExternalWorkerJob job = getExternalWorkerJobById(jobId);

        if (!workerId.equals(job.getLockOwner())) {
            throw new FlowableForbiddenException(workerId + " does not hold a lock on the requested job");
        }

        if (ScopeTypes.CMMN.equals(job.getScopeType())) {
            if (cmmnManagementService != null) {
                if (restApiInterceptor != null) {
                    restApiInterceptor.cmmnTerminateExternalWorkerJob(job, request);
                }

                cmmnManagementService.createCmmnExternalWorkerTransitionBuilder(job.getId(), workerId)
                        .variables(extractVariables(request.getVariables()))
                        .terminate();
            } else {
                throw new FlowableException("Cannot complete CMMN job. There is no CMMN engine available");
            }
        } else {
            throw new FlowableIllegalArgumentException(
                    "Can only terminate CMMN external job. Job with id '" + jobId + "' is from scope '" + job.getScopeType() + "'");
        }

        return ResponseEntity.noContent().build();
    }
@Test
    @CmmnDeployment(resources = "org/flowable/external/job/rest/service/api/simpleExternalWorkerJob.cmmn")
    void terminateCmmnJob() {
        cmmnRuntimeService.createCaseInstanceBuilder()
                .caseDefinitionKey("simpleExternalWorker")
                .start();

        assertThat(cmmnTaskService.createTaskQuery().list()).isEmpty();

        ExternalWorkerJob externalWorkerJob = managementService.createExternalWorkerJobQuery().singleResult();
        assertThat(externalWorkerJob).isNotNull();

        ObjectNode request = objectMapper.createObjectNode();
        request.put("workerId", "testWorker");

        ResponseEntity<String> response = restTemplate
                .postForEntity("/service/acquire/jobs/{jobId}/cmmnTerminate", request, String.class, externalWorkerJob.getId());

        assertThat(response.getStatusCode()).as(response.toString()).isEqualTo(HttpStatus.FORBIDDEN);
        String body = response.getBody();
        assertThat(body).isNotNull();
        assertThatJson(body)
                .isEqualTo("{"
                        + "  message: 'Forbidden',"
                        + "  exception: 'testWorker does not hold a lock on the requested job'"
                        + "}");

        managementService.createExternalWorkerJobAcquireBuilder()
                .topic("simple", Duration.ofMinutes(10))
                .acquireAndLock(1, "testWorker1");

        request = objectMapper.createObjectNode();
        request.put("workerId", "testWorker2");

        response = restTemplate
                .postForEntity("/service/acquire/jobs/{jobId}/cmmnTerminate", request, String.class, externalWorkerJob.getId());

        assertThat(response.getStatusCode()).as(response.toString()).isEqualTo(HttpStatus.FORBIDDEN);
        body = response.getBody();
        assertThat(body).isNotNull();
        assertThatJson(body)
                .isEqualTo("{"
                        + "  message: 'Forbidden',"
                        + "  exception: 'testWorker2 does not hold a lock on the requested job'"
                        + "}");

        request = objectMapper.createObjectNode();
        request.put("workerId", "testWorker1");

        response = restTemplate
                .postForEntity("/service/acquire/jobs/{jobId}/cmmnTerminate", request, String.class, externalWorkerJob.getId());

        assertThat(response.getStatusCode()).as(response.toString()).isEqualTo(HttpStatus.NO_CONTENT);
        body = response.getBody();
        assertThat(body).isNull();

        CmmnJobTestHelper.waitForJobExecutorToProcessAllJobs(cmmnEngineConfiguration, 4000, 300, true);

        assertThat(cmmnTaskService.createTaskQuery().list())
                .extracting(Task::getTaskDefinitionKey)
                .containsExactlyInAnyOrder("afterExternalWorkerTerminateTask");
    }