content: /*
   * Copyright 2017-2025 Hyland Software, Inc. and its affiliates.
   *
   * 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.
   */
  /*
   * 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.cloud.services.rest.controllers;
  
  import static java.util.Collections.emptyList;
  
  import java.nio.charset.StandardCharsets;
  import java.util.Optional;
  import org.activiti.api.process.model.ProcessInstance;
  import org.activiti.api.process.model.builders.ProcessPayloadBuilder;
  import org.activiti.api.process.model.payloads.CreateProcessInstancePayload;
  import org.activiti.api.process.model.payloads.ReceiveMessagePayload;
  import org.activiti.api.process.model.payloads.SignalPayload;
  import org.activiti.api.process.model.payloads.StartMessagePayload;
  import org.activiti.api.process.model.payloads.StartProcessPayload;
  import org.activiti.api.process.model.payloads.UpdateProcessPayload;
  import org.activiti.api.process.runtime.ProcessRuntime;
  import org.activiti.api.runtime.shared.query.Page;
  import org.activiti.bpmn.model.BpmnModel;
  import org.activiti.cloud.alfresco.data.domain.AlfrescoPagedModelAssembler;
  import org.activiti.cloud.api.process.model.CloudProcessInstance;
  import org.activiti.cloud.services.core.ProcessDiagramGeneratorWrapper;
  import org.activiti.cloud.services.core.ProcessVariablesPayloadConverter;
  import org.activiti.cloud.services.core.pageable.SpringPageConverter;
  import org.activiti.cloud.services.rest.api.ProcessInstanceController;
  import org.activiti.cloud.services.rest.assemblers.ProcessInstanceRepresentationModelAssembler;
  import org.activiti.engine.RepositoryService;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.data.domain.Pageable;
  import org.springframework.hateoas.EntityModel;
  import org.springframework.hateoas.MediaTypes;
  import org.springframework.hateoas.PagedModel;
  import org.springframework.http.HttpStatus;
  import org.springframework.http.MediaType;
  import org.springframework.http.ResponseEntity;
  import org.springframework.web.bind.annotation.PathVariable;
  import org.springframework.web.bind.annotation.RequestBody;
  import org.springframework.web.bind.annotation.RequestMapping;
  import org.springframework.web.bind.annotation.RestController;
  
  @RestController
  @RequestMapping(produces = { MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
  public class ProcessInstanceControllerImpl implements ProcessInstanceController {
  
      private final RepositoryService repositoryService;
  
      private final ProcessDiagramGeneratorWrapper processDiagramGenerator;
  
      private final ProcessInstanceRepresentationModelAssembler representationModelAssembler;
  
      private final AlfrescoPagedModelAssembler<ProcessInstance> pagedCollectionModelAssembler;
  
      private final ProcessRuntime processRuntime;
  
      private final SpringPageConverter pageConverter;
  
      private final ProcessVariablesPayloadConverter variablesPayloadConverter;
  
      @Autowired
      public ProcessInstanceControllerImpl(
          RepositoryService repositoryService,
          ProcessDiagramGeneratorWrapper processDiagramGenerator,
          ProcessInstanceRepresentationModelAssembler representationModelAssembler,
          AlfrescoPagedModelAssembler<ProcessInstance> pagedCollectionModelAssembler,
          ProcessRuntime processRuntime,
          SpringPageConverter pageConverter,
          ProcessVariablesPayloadConverter variablesPayloadConverter
      ) {
          this.repositoryService = repositoryService;
          this.processDiagramGenerator = processDiagramGenerator;
          this.representationModelAssembler = representationModelAssembler;
          this.pagedCollectionModelAssembler = pagedCollectionModelAssembler;
          this.processRuntime = processRuntime;
          this.pageConverter = pageConverter;
          this.variablesPayloadConverter = variablesPayloadConverter;
      }
  
      @Override
      public PagedModel<EntityModel<CloudProcessInstance>> getProcessInstances(Pageable pageable) {
          Page<ProcessInstance> processInstancePage = processRuntime.processInstances(
              pageConverter.toAPIPageable(pageable)
          );
          return pagedCollectionModelAssembler.toModel(
              pageable,
              pageConverter.toSpringPage(pageable, processInstancePage),
              representationModelAssembler
          );
      }
  
      @Override
      public EntityModel<CloudProcessInstance> startProcess(@RequestBody StartProcessPayload startProcessPayload) {
          startProcessPayload = variablesPayloadConverter.convert(startProcessPayload);
  
          return representationModelAssembler.toModel(processRuntime.start(startProcessPayload));
      }
  
      @Override
      public EntityModel<CloudProcessInstance> startCreatedProcess(
          @PathVariable String processInstanceId,
          @RequestBody(required = false) StartProcessPayload startProcessPayload
      ) {
          StartProcessPayload convertedStartProcessPayload = variablesPayloadConverter.convert(
              Optional.ofNullable(startProcessPayload).orElse(ProcessPayloadBuilder.start().build())
          );
          return representationModelAssembler.toModel(
              processRuntime.startCreatedProcess(processInstanceId, convertedStartProcessPayload)
          );
      }
  
      @Override
      public EntityModel<CloudProcessInstance> createProcessInstance(
          @RequestBody CreateProcessInstancePayload createProcessInstancePayload
      ) {
          return representationModelAssembler.toModel(processRuntime.create(createProcessInstancePayload));
      }
  
      @Override
      public EntityModel<CloudProcessInstance> getProcessInstanceById(@PathVariable String processInstanceId) {
          return representationModelAssembler.toModel(processRuntime.processInstance(processInstanceId));
      }
  
      @Override
      public String getProcessDiagram(@PathVariable String processInstanceId) {
          ProcessInstance processInstance = processRuntime.processInstance(processInstanceId);
  
          BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
          return new String(
              processDiagramGenerator.generateDiagram(
                  bpmnModel,
                  processRuntime.processInstanceMeta(processInstance.getId()).getActiveActivitiesIds(),
                  emptyList(),
                  emptyList()
              ),
              StandardCharsets.UTF_8
          );
      }
  
      @Override
      public ResponseEntity<Void> sendSignal(@RequestBody SignalPayload cmd) {
          processRuntime.signal(cmd);
          return new ResponseEntity<>(HttpStatus.OK);
      }
  
      @Override
      public EntityModel<CloudProcessInstance> suspend(@PathVariable String processInstanceId) {
          return representationModelAssembler.toModel(
              processRuntime.suspend(ProcessPayloadBuilder.suspend(processInstanceId))
          );
      }
  
      @Override
      public EntityModel<CloudProcessInstance> resume(@PathVariable String processInstanceId) {
          return representationModelAssembler.toModel(
              processRuntime.resume(ProcessPayloadBuilder.resume(processInstanceId))
          );
      }
  
      @Override
      public EntityModel<CloudProcessInstance> deleteProcessInstance(@PathVariable String processInstanceId) {
          return representationModelAssembler.toModel(
              processRuntime.delete(ProcessPayloadBuilder.delete(processInstanceId))
          );
      }
  
      @Override
      public EntityModel<CloudProcessInstance> updateProcess(
          @PathVariable String processInstanceId,
          @RequestBody UpdateProcessPayload payload
      ) {
          if (payload != null) {
              payload.setProcessInstanceId(processInstanceId);
          }
  
          return representationModelAssembler.toModel(processRuntime.update(payload));
      }
  
      @Override
      public PagedModel<EntityModel<CloudProcessInstance>> subprocesses(
          @PathVariable String processInstanceId,
          Pageable pageable
      ) {
          Page<ProcessInstance> processInstancePage = processRuntime.processInstances(
              pageConverter.toAPIPageable(pageable),
              ProcessPayloadBuilder.subprocesses(processInstanceId)
          );
  
          return pagedCollectionModelAssembler.toModel(
              pageable,
              pageConverter.toSpringPage(pageable, processInstancePage),
              representationModelAssembler
          );
      }
  
      @Override
      public EntityModel<CloudProcessInstance> sendStartMessage(@RequestBody StartMessagePayload startMessagePayload) {
          startMessagePayload = variablesPayloadConverter.convert(startMessagePayload);
  
          ProcessInstance processInstance = processRuntime.start(startMessagePayload);
  
          return representationModelAssembler.toModel(processInstance);
      }
  
      @Override
      public ResponseEntity<Void> receive(@RequestBody ReceiveMessagePayload receiveMessagePayload) {
          processRuntime.receive(receiveMessagePayload);
  
          return new ResponseEntity<>(HttpStatus.OK);
      }
  }
  