content: /*
   * Copyright 2010-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.spring.boot.actuate.endpoint;
  
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import org.activiti.engine.ProcessEngine;
  import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
  import org.activiti.engine.impl.persistence.deploy.DefaultDeploymentCache;
  import org.activiti.engine.impl.persistence.deploy.DeploymentCache;
  import org.activiti.engine.impl.persistence.deploy.ProcessDefinitionCacheEntry;
  import org.activiti.engine.repository.ProcessDefinition;
  import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
  import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
  import org.springframework.boot.context.properties.ConfigurationProperties;
  
  /**
   * Registers a Boot Actuator endpoint that provides information on the
   * running process instance and renders BPMN diagrams of the deployed processes.
   */
  @ConfigurationProperties(prefix = "endpoints.activiti")
  @Endpoint(id = "activiti")
  public class ProcessEngineEndpoint {
  
      private final ProcessEngine processEngine;
  
      public ProcessEngineEndpoint(ProcessEngine processEngine) {
          this.processEngine = processEngine;
      }
  
      @ReadOperation
      public Map<String, Object> invoke() {
          Map<String, Object> metrics = new HashMap<String, Object>();
  
          // Process definitions
          metrics.put(
              "processDefinitionCount",
              processEngine.getRepositoryService().createProcessDefinitionQuery().count()
          );
  
          // List of all process definitions
          List<ProcessDefinition> processDefinitions = processEngine
              .getRepositoryService()
              .createProcessDefinitionQuery()
              .orderByProcessDefinitionKey()
              .asc()
              .list();
          List<String> processDefinitionKeys = new ArrayList<String>();
          for (ProcessDefinition processDefinition : processDefinitions) {
              processDefinitionKeys.add(processDefinition.getKey() + " (v" + processDefinition.getVersion() + ")");
          }
          metrics.put("deployedProcessDefinitions", processDefinitionKeys);
  
          // Process instances
          Map<String, Object> processInstanceCountMap = new HashMap<String, Object>();
          metrics.put("runningProcessInstanceCount", processInstanceCountMap);
          for (ProcessDefinition processDefinition : processDefinitions) {
              processInstanceCountMap.put(
                  processDefinition.getKey() + " (v" + processDefinition.getVersion() + ")",
                  processEngine
                      .getRuntimeService()
                      .createProcessInstanceQuery()
                      .processDefinitionId(processDefinition.getId())
                      .count()
              );
          }
          Map<String, Object> completedProcessInstanceCountMap = new HashMap<String, Object>();
          metrics.put("completedProcessInstanceCount", completedProcessInstanceCountMap);
          for (ProcessDefinition processDefinition : processDefinitions) {
              completedProcessInstanceCountMap.put(
                  processDefinition.getKey() + " (v" + processDefinition.getVersion() + ")",
                  processEngine
                      .getHistoryService()
                      .createHistoricProcessInstanceQuery()
                      .finished()
                      .processDefinitionId(processDefinition.getId())
                      .count()
              );
          }
  
          // Open tasks
          metrics.put("openTaskCount", processEngine.getTaskService().createTaskQuery().count());
          metrics.put(
              "completedTaskCount",
              processEngine.getHistoryService().createHistoricTaskInstanceQuery().finished().count()
          );
  
          // Tasks completed today
          metrics.put(
              "completedTaskCountToday",
              processEngine
                  .getHistoryService()
                  .createHistoricTaskInstanceQuery()
                  .finished()
                  .taskCompletedAfter(new Date(System.currentTimeMillis() - secondsForDays(1)))
                  .count()
          );
  
          // Process steps
          metrics.put(
              "completedActivities",
              processEngine.getHistoryService().createHistoricActivityInstanceQuery().finished().count()
          );
  
          // Process definition cache
          DeploymentCache<ProcessDefinitionCacheEntry> deploymentCache =
              ((ProcessEngineConfigurationImpl) processEngine.getProcessEngineConfiguration()).getProcessDefinitionCache();
          if (deploymentCache instanceof DefaultDeploymentCache) {
              metrics.put("cachedProcessDefinitionCount", ((DefaultDeploymentCache) deploymentCache).size());
          }
          return metrics;
      }
  
      private long secondsForDays(int days) {
          int hour = 60 * 60 * 1000;
          int day = 24 * hour;
          return days * day;
      }
  }
  