All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sap.cloud.lm.sl.slp.activiti.ActivitiFacade Maven / Gradle / Ivy

package com.sap.cloud.lm.sl.slp.activiti;

import static java.text.MessageFormat.format;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.activiti.engine.ActivitiOptimisticLockingException;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.history.HistoricVariableInstanceQuery;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ExecutionQuery;
import org.activiti.engine.runtime.Job;
import org.activiti.engine.runtime.JobQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sap.activiti.common.ExecutionStatus;
import com.sap.activiti.common.actions.LogicalStepNameProvider;
import com.sap.activiti.common.actions.LogicalStepNameProviderException;
import com.sap.cloud.lm.sl.slp.Constants;
import com.sap.cloud.lm.sl.slp.message.Messages;

/**
 * Facade class for providing access to the functionalities of an Activiti process engine.
 */
public class ActivitiFacade {

    private static final Logger LOGGER = LoggerFactory.getLogger(ActivitiFacade.class);

    private static final int DEFAULT_ABORT_TIMEOUT_MS = 30000;
    private static final long GET_EXECUTION_RETRY_INTERVAL_MS = 100;

    // Singleton instance
    private static final ActivitiFacade INSTANCE = new ActivitiFacade();

    private ProcessEngine engine;

    /**
     * Returns the singleton instance of this class.
     * 
     * @return the singleton instance of the class
     */
    public static ActivitiFacade getInstance() {
        return INSTANCE;
    }

    protected ActivitiFacade() {
    }

    /**
     * Initializes the instance with an Activiti process engine.
     * 
     * @param engine an Activiti process engine
     */
    public void init(ProcessEngine engine) {
        this.engine = engine;
    }

    public ProcessInstance startProcessInstance(String userId, String processDefinitionKey, Map variables) {
        try {
            engine.getIdentityService().setAuthenticatedUserId(userId);
            // Get the last deployed version of the process and start a process instance
            ProcessDefinitionQuery query = engine.getRepositoryService().createProcessDefinitionQuery().processDefinitionKey(
                processDefinitionKey).latestVersion();
            String processDefinitionId = query.singleResult().getId();
            ProcessInstance processInstance = engine.getRuntimeService().startProcessInstanceById(processDefinitionId, variables);
            return processInstance;
        } finally {
            // After the setAuthenticatedUserId() method is invoked, all Activiti service methods
            // executed within the current thread will have access to this userId. Just before
            // leaving the method, the userId is set to null, preventing other services from using
            // it unintentionally.
            engine.getIdentityService().setAuthenticatedUserId(null);
        }
    }

    public void deleteProcessInstance(String userId, String processInstanceId, String deleteReason) {
        try {
            engine.getIdentityService().setAuthenticatedUserId(userId);

            long deadline = System.currentTimeMillis() + DEFAULT_ABORT_TIMEOUT_MS;
            while (true) {
                try {
                    LOGGER.debug(format(Messages.SETTING_VARIABLE, Constants.PROCESS_ABORTED, Boolean.TRUE));
                    // TODO: Use execution ID instead of process instance ID, as they can be
                    // different if the process has parallel executions.
                    engine.getRuntimeService().setVariable(processInstanceId, Constants.PROCESS_ABORTED, Boolean.TRUE);
                    LOGGER.debug(format(Messages.SET_SUCCESSFULLY, Constants.PROCESS_ABORTED));

                    engine.getRuntimeService().deleteProcessInstance(processInstanceId, deleteReason);
                    break;
                } catch (ActivitiOptimisticLockingException e) {
                    if (isPastDeadline(deadline)) {
                        throw new IllegalStateException(Messages.ABORT_OPERATION_TIMED_OUT, e);
                    }
                    LOGGER.warn(format(Messages.RETRYING_PROCESS_ABORT, processInstanceId));
                }
            }
        } finally {
            engine.getIdentityService().setAuthenticatedUserId(null);
        }
    }

    protected boolean isPastDeadline(long deadline) {
        return System.currentTimeMillis() >= deadline;
    }

    void deleteHistoricProcessInstance(String userId, String processInstanceId) {
        try {
            engine.getIdentityService().setAuthenticatedUserId(userId);
            engine.getHistoryService().deleteHistoricProcessInstance(processInstanceId);
        } finally {
            engine.getIdentityService().setAuthenticatedUserId(null);
        }
    }

    public void signal(String userId, String executionId) {
        try {
            engine.getIdentityService().setAuthenticatedUserId(userId);
            engine.getRuntimeService().signal(executionId);
        } finally {
            engine.getIdentityService().setAuthenticatedUserId(null);
        }
    }

    /**
     * Execute a 'signal' to the activity, specified by processId and activitiId. The operation is blocking and it retries to 'signal' the
     * activity till either the 'signal' is possible (the activity to be signaled is the current one) or timeoutInMillis is reached.
     * 
     */
    public void signal(String userId, String processId, String activityId, Map variables, long timeoutInMillis) {
        String executionId = getExecutionId(processId, activityId, timeoutInMillis);
        LOGGER.info(format("Found execution with id:{0} for process with id:{1} and activity id:{2}", executionId, processId, activityId));
        try {
            engine.getIdentityService().setAuthenticatedUserId(userId);
            engine.getRuntimeService().signal(executionId, variables);
        } catch (Exception e) { // NOSONAR
            LOGGER.error(format("Failed to signal execution with id:{0} for process with id:{1} and activity id:{2}", executionId,
                processId, activityId), e);
            throw e;
        } finally {
            engine.getIdentityService().setAuthenticatedUserId(null);
        }

    }

    private String getExecutionId(String processId, String activityId, long timeoutInMillis) {
        long deadline = System.currentTimeMillis() + timeoutInMillis;
        while (true) {
            Execution execution = engine.getRuntimeService().createExecutionQuery().processInstanceId(processId).activityId(
                activityId).singleResult();
            if (execution != null && execution.getParentId() != null) {
                return execution.getId();
            }
            if (isPastDeadline(deadline)) {
                IllegalStateException timeoutException = new IllegalStateException(
                    format(Messages.PROCESS_STEP_NOT_REACHED_BEFORE_TIMEOUT, activityId, processId));
                LOGGER.error(timeoutException.toString(), timeoutException);
                throw timeoutException;
            }
            try {
                Thread.sleep(GET_EXECUTION_RETRY_INTERVAL_MS);
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
        }
    }

    public Execution getProcessExecution(String processInstanceId) {
        return getExecutionQuery(processInstanceId).singleResult();
    }

    public List getProcessExecutions(String processInstanceId) {
        return getExecutionQuery(processInstanceId).list();
    }

    private ExecutionQuery getExecutionQuery(String processInstanceId) {
        return engine.getRuntimeService().createExecutionQuery().processInstanceId(processInstanceId);
    }

    protected long getExecutionRetryIntervalMs() {
        return GET_EXECUTION_RETRY_INTERVAL_MS;
    }

    public String getServiceId(String processInstanceId) {
        HistoricVariableInstance historicVariableInstance = getHistoricVariableInstance(processInstanceId,
            Constants.VARIABLE_NAME_SERVICE_ID);
        return historicVariableInstance != null ? (String) historicVariableInstance.getValue() : null;
    }

    ProcessInstance getActiveProcessInstance(String processDefinitionKey, String spaceId, String processInstanceId) {
        ProcessInstanceQuery query = engine.getRuntimeService().createProcessInstanceQuery().processDefinitionKey(
            processDefinitionKey).variableValueEquals(Constants.VARIABLE_NAME_SPACE_ID, spaceId).excludeSubprocesses(
                true).processInstanceId(processInstanceId);
        return query.singleResult();
    }

    public ProcessInstance getActiveProcessInstance(String processInstanceId) {
        return engine.getRuntimeService().createProcessInstanceQuery().processInstanceId(processInstanceId).excludeSubprocesses(
            true).singleResult();
    }

    List getActiveProcessInstances(String processDefinitionKey, String spaceId) {
        ProcessInstanceQuery query = engine.getRuntimeService().createProcessInstanceQuery().processDefinitionKey(
            processDefinitionKey).variableValueEquals(Constants.VARIABLE_NAME_SPACE_ID, spaceId).excludeSubprocesses(true);
        return query.list();
    }

    HistoricProcessInstance getHistoricProcessInstance(String processDefinitionKey, String spaceId, String processInstanceId) {
        HistoricProcessInstanceQuery query = engine.getHistoryService().createHistoricProcessInstanceQuery().processDefinitionKey(
            processDefinitionKey).variableValueEquals(Constants.VARIABLE_NAME_SPACE_ID, spaceId).excludeSubprocesses(
                true).processInstanceId(processInstanceId);

        return query.singleResult();
    }

    HistoricProcessInstance getHistoricProcessInstance(String processInstanceId, String spaceId) {
        HistoricProcessInstanceQuery query = engine.getHistoryService().createHistoricProcessInstanceQuery().variableValueEquals(
            Constants.VARIABLE_NAME_SPACE_ID, spaceId).excludeSubprocesses(true).processInstanceId(processInstanceId);
        return query.singleResult();
    }

    List getHistoricProcessInstances(String processDefinitionKey, String spaceId) {
        HistoricProcessInstanceQuery query = engine.getHistoryService().createHistoricProcessInstanceQuery().processDefinitionKey(
            processDefinitionKey).variableValueEquals(Constants.VARIABLE_NAME_SPACE_ID, spaceId).excludeSubprocesses(true);
        return query.list();
    }

    List getHistoricActivityInstances(String processInstanceId) {
        HistoricActivityInstanceQuery query = engine.getHistoryService().createHistoricActivityInstanceQuery().processInstanceId(
            processInstanceId).orderByHistoricActivityInstanceStartTime().asc();
        return query.list();
    }

    List getHistoricVariableInstances(String processInstanceId) {
        HistoricVariableInstanceQuery query = engine.getHistoryService().createHistoricVariableInstanceQuery().processInstanceId(
            processInstanceId);
        return query.list();
    }

    public HistoricVariableInstance getHistoricVariableInstance(String processInstanceId, String variableName) {
        HistoricVariableInstanceQuery query = engine.getHistoryService().createHistoricVariableInstanceQuery().processInstanceId(
            processInstanceId).variableName(variableName);
        return query.singleResult();
    }

    List getHistoricActivities(String activityType, String processInstanceId) {
        return engine.getHistoryService().createHistoricActivityInstanceQuery().activityType(activityType).processInstanceId(
            processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list();
    }

    public String getActivityType(String processInstanceId, String activityId) {
        HistoricActivityInstance historicInstance = engine.getHistoryService().createHistoricActivityInstanceQuery().processInstanceId(
            processInstanceId).activityId(activityId).singleResult();
        return historicInstance != null ? historicInstance.getActivityType() : null;
    }

    public List getHistoricSubProcessIds(String superProcessId) {
        List subProcessIds = new ArrayList<>();
        List variablesWithSuperProcessId = retrieveVariablesByCorrelationId(superProcessId);
        for (HistoricVariableInstance historicVariableInstance : variablesWithSuperProcessId) {
            if (!historicVariableInstance.getProcessInstanceId().equals(superProcessId)) {
                subProcessIds.add(historicVariableInstance.getProcessInstanceId());
            }
        }

        return subProcessIds;
    }

    List retrieveVariablesByCorrelationId(String superProcessId) {
        return engine.getHistoryService().createHistoricVariableInstanceQuery().variableValueEquals(Constants.CORRELATION_ID,
            superProcessId).orderByProcessInstanceId().asc().list();

    }

    public List getActiveHistoricSubProcessIds(String superProcessId) {
        List subProcessIds = getHistoricSubProcessIds(superProcessId);
        List activeSubProcessIds = new ArrayList<>();
        for (String subProcessId : subProcessIds) {
            HistoricActivityInstance subProcessEndActivity = getHistoricActivitiInstance(subProcessId, "endEvent");
            if (subProcessEndActivity == null) {
                activeSubProcessIds.add(subProcessId);
            }
        }

        return activeSubProcessIds;
    }

    HistoricActivityInstance getHistoricActivitiInstance(String processId, String activityType) {
        return engine.getHistoryService().createHistoricActivityInstanceQuery().activityType(activityType).processInstanceId(
            processId).singleResult();
    }

    public Job getJob(String processInstanceId) {
        JobQuery query = engine.getManagementService().createJobQuery().processInstanceId(processInstanceId);
        return query.singleResult();
    }

    public void executeJob(String userId, String processInstanceId) {
        Job job = getJob(processInstanceId);
        if (job != null) {
            try {
                engine.getIdentityService().setAuthenticatedUserId(userId);
                setStatusVariable(processInstanceId, job);
                engine.getManagementService().executeJob(job.getId());
            } finally {
                engine.getIdentityService().setAuthenticatedUserId(null);
            }
        }
    }

    private void setStatusVariable(String processInstanceId, Job job) {
        try {
            LogicalStepNameProvider lsnp = new LogicalStepNameProvider(engine, job);
            String statusVariable = com.sap.activiti.common.Constants.STEP_NAME_PREFIX + lsnp.getLogicalStepName();
            engine.getRuntimeService().setVariable(processInstanceId, statusVariable, ExecutionStatus.FAILED.name());
        } catch (LogicalStepNameProviderException e) {
            LOGGER.warn(e.getMessage());
        }
    }

    public void setRuntimeVariables(String processInstanceId, Map variables) {
        engine.getRuntimeService().setVariables(processInstanceId, variables);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy