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.
   */
  package org.activiti.cloud.services.rest.controllers;
  
  import java.util.ArrayList;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Set;
  import org.activiti.bpmn.model.ExtensionElement;
  import org.activiti.bpmn.model.FlowElement;
  import org.activiti.bpmn.model.Process;
  import org.activiti.bpmn.model.ServiceTask;
  import org.activiti.bpmn.model.UserTask;
  import org.activiti.cloud.services.api.model.ProcessDefinitionMeta;
  import org.activiti.cloud.services.api.model.ProcessDefinitionServiceTask;
  import org.activiti.cloud.services.api.model.ProcessDefinitionUserTask;
  import org.activiti.cloud.services.api.model.ProcessDefinitionVariable;
  import org.activiti.cloud.services.rest.api.ProcessDefinitionMetaController;
  import org.activiti.cloud.services.rest.assemblers.ProcessDefinitionMetaRepresentationModelAssembler;
  import org.activiti.engine.ActivitiObjectNotFoundException;
  import org.activiti.engine.RepositoryService;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.hateoas.EntityModel;
  import org.springframework.web.bind.annotation.PathVariable;
  import org.springframework.web.bind.annotation.RestController;
  
  @RestController
  public class ProcessDefinitionMetaControllerImpl implements ProcessDefinitionMetaController {
  
      private final RepositoryService repositoryService;
      private final ProcessDefinitionMetaRepresentationModelAssembler representationModelAssembler;
  
      @Autowired
      public ProcessDefinitionMetaControllerImpl(
          RepositoryService repositoryService,
          ProcessDefinitionMetaRepresentationModelAssembler representationModelAssembler
      ) {
          this.repositoryService = repositoryService;
          this.representationModelAssembler = representationModelAssembler;
      }
  
      @Override
      public EntityModel<ProcessDefinitionMeta> getProcessDefinitionMetadata(@PathVariable String id) {
          org.activiti.engine.repository.ProcessDefinition processDefinition = repositoryService
              .createProcessDefinitionQuery()
              .processDefinitionId(id)
              .singleResult();
          if (processDefinition == null) {
              throw new ActivitiObjectNotFoundException(
                  "Unable to find process definition for the given id:'" + id + "'"
              );
          }
  
          List<Process> processes = repositoryService.getBpmnModel(id).getProcesses();
          Set<ProcessDefinitionVariable> variables = new HashSet<>();
          Set<String> users = new HashSet<>();
          Set<String> groups = new HashSet<>();
          Set<ProcessDefinitionUserTask> userTasks = new HashSet<>();
          Set<ProcessDefinitionServiceTask> serviceTasks = new HashSet<>();
  
          for (Process process : processes) {
              variables.addAll(getVariables(process));
              List<FlowElement> flowElementList = (List<FlowElement>) process.getFlowElements();
              for (FlowElement flowElement : flowElementList) {
                  if (flowElement.getClass().equals(UserTask.class)) {
                      UserTask userTask = (UserTask) flowElement;
                      ProcessDefinitionUserTask task = new ProcessDefinitionUserTask(
                          userTask.getName(),
                          userTask.getDocumentation()
                      );
                      userTasks.add(task);
                      users.addAll(userTask.getCandidateUsers());
                      groups.addAll(userTask.getCandidateGroups());
                  }
                  if (flowElement.getClass().equals(ServiceTask.class)) {
                      ServiceTask serviceTask = (ServiceTask) flowElement;
                      ProcessDefinitionServiceTask task = new ProcessDefinitionServiceTask(
                          serviceTask.getName(),
                          serviceTask.getImplementation()
                      );
                      serviceTasks.add(task);
                  }
              }
          }
  
          return representationModelAssembler.toModel(
              new ProcessDefinitionMeta(
                  processDefinition.getId(),
                  processDefinition.getName(),
                  processDefinition.getDescription(),
                  processDefinition.getVersion(),
                  users,
                  groups,
                  variables,
                  userTasks,
                  serviceTasks
              )
          );
      }
  
      private List<ProcessDefinitionVariable> getVariables(Process process) {
          List<ProcessDefinitionVariable> variables = new ArrayList<>();
          if (!process.getExtensionElements().isEmpty()) {
              Iterator<List<ExtensionElement>> it = process.getExtensionElements().values().iterator();
              while (it.hasNext()) {
                  List<ExtensionElement> extensionElementList = it.next();
                  Iterator<ExtensionElement> it2 = extensionElementList.iterator();
                  while (it2.hasNext()) {
                      ExtensionElement ee = it2.next();
                      String name = ee.getAttributeValue(ee.getNamespace(), "variableName");
                      String type = ee.getAttributeValue(ee.getNamespace(), "variableType");
                      ProcessDefinitionVariable variable = new ProcessDefinitionVariable(name, type);
                      variables.add(variable);
                  }
              }
          }
          return variables;
      }
  }
  