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

com.centurylink.mdw.services.process.ProcessExecutor Maven / Gradle / Ivy

There is a newer version: 6.1.39
Show newest version
/*
 * Copyright (C) 2017 CenturyLink, Inc.
 *
 * 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 com.centurylink.mdw.services.process;

import com.centurylink.mdw.activity.ActivityException;
import com.centurylink.mdw.cache.asset.PackageCache;
import com.centurylink.mdw.common.MdwException;
import com.centurylink.mdw.config.PropertyManager;
import com.centurylink.mdw.constant.PropertyNames;
import com.centurylink.mdw.dataaccess.DataAccessException;
import com.centurylink.mdw.dataaccess.DatabaseAccess;
import com.centurylink.mdw.dataaccess.RetryableTransaction;
import com.centurylink.mdw.model.event.EventWaitInstance;
import com.centurylink.mdw.model.event.InternalEvent;
import com.centurylink.mdw.model.request.Response;
import com.centurylink.mdw.model.variable.Document;
import com.centurylink.mdw.model.variable.DocumentReference;
import com.centurylink.mdw.model.variable.VariableInstance;
import com.centurylink.mdw.model.workflow.Package;
import com.centurylink.mdw.model.workflow.Process;
import com.centurylink.mdw.model.workflow.*;
import com.centurylink.mdw.service.data.process.EngineDataAccess;
import com.centurylink.mdw.service.data.process.EngineDataAccessCache;
import com.centurylink.mdw.service.data.process.ProcessCache;
import com.centurylink.mdw.services.EventException;
import com.centurylink.mdw.services.ProcessException;
import com.centurylink.mdw.services.messenger.InternalMessenger;
import com.centurylink.mdw.util.TransactionUtil;
import com.centurylink.mdw.util.TransactionWrapper;
import com.centurylink.mdw.util.log.LoggerUtil;
import com.centurylink.mdw.util.log.StandardLogger;
import org.apache.commons.lang.StringUtils;

import javax.transaction.SystemException;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Map;

public class ProcessExecutor implements RetryableTransaction {

    private final ProcessExecutorImpl engineImpl;

    private int transactionRetryCount = 0;
    private int transactionRetryMax = -1;
    private int transactionRetryInterval = -1;

    public ProcessExecutor(EngineDataAccess edao, InternalMessenger internalMessenger, boolean forServiceProcess) {
        engineImpl = new ProcessExecutorImpl(edao, internalMessenger, forServiceProcess);
        engineImpl.activityTimings = PropertyManager.getBooleanProperty(PropertyNames.MDW_TIMINGS_ACTIVITIES, false);
    }

    ProcessExecutor(ProcessExecutorImpl engineImpl) {
        this.engineImpl = engineImpl;
    }

    public ProcessInstance createProcessInstance(Long processId, String ownerType, Long ownerId,
            String secondaryOwnerType, Long secondaryOwnerId, String masterRequestId, Map values)
            throws ProcessException, DataAccessException {

        String label = null, template = null;
        Process process;
        try {
            process = ProcessCache.getProcess(processId);
        } catch (IOException ex) {
            throw new ProcessException("Cannot load process " + processId, ex);
        }
        if (process != null) {
            String pkgName = process.getPackageName();
            if (StringUtils.isBlank(pkgName)) { // should never happen, but just in case
                Package pkg = PackageCache.getPackage(process.getPackageName());
                if (pkg != null)
                    pkgName = pkg.getName();
            }
            if (process.getName().startsWith("$") && values.containsKey(process.getName())) {
                // template process -- name is provided in params
                label = values.get(process.getName()).toString();
                values.remove(process.getName());
                template = process.getLabel();
                if (!StringUtils.isBlank(pkgName))
                    template = pkgName + "/" + template;
            }
            else {
                label = process.getLabel();
                if (!StringUtils.isBlank(pkgName))
                    label = pkgName + "/" + label;
            }
        }

        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.createProcessInstance(processId, ownerType,
                    ownerId, secondaryOwnerType, secondaryOwnerId,
                    masterRequestId, values, label, template);
        } catch (MdwException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).createProcessInstance(processId, ownerType,
                        ownerId, secondaryOwnerType, secondaryOwnerId, masterRequestId, values);
            }
            else {
                throw ex;
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public ProcessInstance getProcessInstance(Long procInstId) throws ProcessException, DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.getDataAccess().getProcessInstance(procInstId);
        } catch (DataAccessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).getProcessInstance(procInstId);
            }
            else {
                throw ex;
            }
        } catch (SQLException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).getProcessInstance(procInstId);
            }
            else {
                throw new ProcessException(0, "Failed to load process instance:" + procInstId, ex);
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public void startProcessInstance(ProcessInstance processInst, int delay)
            throws ProcessException, DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.startProcessInstance(processInst, delay);
        } catch (ProcessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).startProcessInstance(processInst, delay);
            }
            else {
                throw ex;
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public void handleProcessFinish(InternalEvent event) throws ProcessException, DataAccessException {
        TransactionWrapper transaction=null;
        try {
            transaction = startTransaction();
            engineImpl.handleProcessFinish(event);
        } catch (MdwException e) {
            if (canRetryTransaction(e)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).handleProcessFinish(event);
            }
            else {
                throw e;
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public void updateProcessInstanceStatus(Long pProcInstId, Integer status)
    throws DataAccessException,ProcessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.updateProcessInstanceStatus(pProcInstId, status);
        } catch (MdwException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).updateProcessInstanceStatus(pProcInstId, status);
            }
            else {
                throw ex;
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public void abortProcessInstance(InternalEvent event) throws ProcessException, DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.abortProcessInstance(event);
        } catch (MdwException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).abortProcessInstance(event);
            }
            else {
                throw ex;
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public void setProcessInstanceCompletionCode(Long procInstId, String completionCode)
            throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.getDataAccess().setProcessInstanceCompletionCode(procInstId, completionCode);
        } catch (DataAccessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).setProcessInstanceCompletionCode(procInstId, completionCode);
            }
            else {
                throw ex;
            }
        } catch (SQLException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).setProcessInstanceCompletionCode(procInstId, completionCode);
            }
            else {
                throw new DataAccessException("Failed to set process instance completion code", ex);
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public void setProcessInstanceStartTime(Long processInstanceId) throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.getDataAccess().setProcessInstanceStartTime(processInstanceId);
        } catch (DataAccessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).setProcessInstanceStartTime(processInstanceId);
            }
            else {
                throw ex;
            }
        } catch (SQLException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).setProcessInstanceStartTime(processInstanceId);
            }
            else {
                throw new DataAccessException(0, "Failed to set process instance completion code", ex);
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public ActivityInstance getActivityInstance(Long actInstId) throws ProcessException, DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.getDataAccess().getActivityInstance(actInstId);
        } catch (DataAccessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).getActivityInstance(actInstId);
            }
            else {
                throw ex;
            }
        } catch (SQLException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).getActivityInstance(actInstId);
            }
            else {
                throw new ProcessException("Failed to get activity instance", ex);
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public void executeActivityInstance(BaseActivity activity) throws ActivityException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            if (activity.getTimer() != null) {
                activity.executeTimed(this);
            } else {
                activity.execute(this);
            }
        } catch (DataAccessException ex) {
            throw new ActivityException(-1, "Failed to execute activity", ex);
        } finally {
            try {
                stopTransaction(transaction);
            } catch (DataAccessException ex) {
                LoggerUtil.getStandardLogger().error("Fail to stop transaction in execute()", ex);
            }
        }
    }

    public void failActivityInstance(InternalEvent event, ProcessInstance processInst, Long activityId,
            Long activityInstId, BaseActivity activity, Throwable cause) {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.failActivityInstance(event,
                    processInst, activityId, activityInstId,
                    activity, cause);
        } catch (MdwException | SQLException ex) {
            if (canRetryTransaction(ex)) {
                try {
                    transaction = (TransactionWrapper)initTransactionRetry(transaction);
                    ((ProcessExecutor)getTransactionRetrier()).failActivityInstance(event, processInst, activityId, activityInstId, activity, cause);
                } catch (DataAccessException ex1) {
                    StandardLogger logger = LoggerUtil.getStandardLogger();
                    logger.error("Exception thrown during failActivityInstance", ex1);
                }
            }
            else {
                StandardLogger logger = LoggerUtil.getStandardLogger();
                logger.error("Exception thrown during failActivityInstance", ex);
            }
        } finally {
            try {
                stopTransaction(transaction);
            } catch (DataAccessException ex) {
                StandardLogger logger = LoggerUtil.getStandardLogger();
                logger.error("Fail to stop transaction in failActivityInstance", ex);
            }
        }
    }

    public DocumentReference createActivityExceptionDocument(ProcessInstance processInst, ActivityInstance actInst,
            BaseActivity activityImpl, Throwable cause) throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.createActivityExceptionDocument(processInst, actInst, activityImpl, cause);
        } catch (DataAccessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper) initTransactionRetry(transaction);
                return ((ProcessExecutor) getTransactionRetrier()).createActivityExceptionDocument(processInst, actInst, activityImpl, cause);
            }
            else {
                throw ex;
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public DocumentReference createProcessExceptionDocument(ProcessInstance processInst, Throwable cause)
            throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.createProcessExceptionDocument(processInst, cause);
        } catch (DataAccessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper) initTransactionRetry(transaction);
                return ((ProcessExecutor) getTransactionRetrier()).createProcessExceptionDocument(processInst, cause);
            }
            else {
                throw ex;
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public ActivityRuntime prepareActivityInstance(InternalEvent event, ProcessInstance procInst)
            throws ProcessException, DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.prepareActivityInstance(event, procInst);
        } finally {
            stopTransaction(transaction);
        }
    }

    public void cancelActivityInstance(ActivityInstance actInst, ProcessInstance procinst, String pStatusMsg)
            throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.cancelActivityInstance(actInst, procinst, pStatusMsg);
        } catch (MdwException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).cancelActivityInstance(actInst, procinst, pStatusMsg);
            }
            else {
                throw ex;
            }
        } catch (SQLException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).cancelActivityInstance(actInst, procinst, pStatusMsg);
            }
            else {
                throw new DataAccessException("Failed to set activity instance status to cancel", ex);
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public void holdActivityInstance(ActivityInstance actInst, Long procId) throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.holdActivityInstance(actInst, procId);
        } catch (MdwException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).holdActivityInstance(actInst, procId);
            }
            else {
                throw ex;
            }
        } catch (SQLException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).holdActivityInstance(actInst, procId);
            }
            else {
                throw new DataAccessException("Failed to set activity instance status to hold", ex);
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public CompletionCode finishActivityInstance(BaseActivity activity, ProcessInstance pi, ActivityInstance ai,
            InternalEvent event, boolean bypassWait) throws ProcessException, DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.finishActivityInstance(activity, pi, ai, event, bypassWait);
        }
        catch (MdwException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).finishActivityInstance(activity, pi, ai, event, bypassWait);
            }
            else {
                throw ex;
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public ActivityRuntime resumeActivityPrepare(ProcessInstance procInst, InternalEvent event, boolean resumeOnHold)
            throws ProcessException, DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.resumeActivityPrepare(procInst, event, resumeOnHold);
        }
        catch (MdwException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).resumeActivityPrepare(procInst, event, resumeOnHold);
            }
            else {
                throw ex;
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public boolean resumeActivityExecute(ActivityRuntime ar, InternalEvent event, boolean resumeOnHold)
        throws ActivityException, DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.resumeActivityExecute(ar, event, resumeOnHold);
        } finally {
            stopTransaction(transaction);
        }
    }

    public void resumeActivityFinish(ActivityRuntime ar, boolean finished, InternalEvent event, boolean resumeOnHold)
            throws ProcessException,DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.resumeActivityFinish(ar, finished, event, resumeOnHold);
        } finally {
            stopTransaction(transaction);
        }
    }

    public void resumeActivityException(ProcessInstance procInst, Long actInstId, BaseActivity activity,
            Throwable cause) {
        TransactionWrapper transaction=null;
        try {
            transaction = startTransaction();
            engineImpl.resumeActivityException(procInst, actInstId, activity, cause);
        } catch (DataAccessException ex) {
            StandardLogger logger = LoggerUtil.getStandardLogger();
            logger.error("Failed to process resume activity exception", ex);
        } finally {
            try {
                stopTransaction(transaction);
            } catch (DataAccessException ex) {
                StandardLogger logger = LoggerUtil.getStandardLogger();
                logger.error("Fail to stop transaction in resumeActivityException", ex);
            }
        }
    }

    public Long getRequestCompletionTime(String ownerType, Long ownerId) throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.getDataAccess().getRequestCompletionTime(ownerType, ownerId);
        } catch (SQLException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).getRequestCompletionTime(ownerType, ownerId);
            }
            else {
                throw new DataAccessException("Failed to get request completion time", ex);
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public void setElapsedTime(String ownerType, Long instanceId, Long elapsedTime) throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.getDataAccess().setElapsedTime(ownerType, instanceId, elapsedTime);
        } catch (SQLException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).setElapsedTime(ownerType, instanceId, elapsedTime);
            }
            else {
                throw new DataAccessException("Failed to set elapsed time", ex);
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public void setActivityInstanceStatus(ActivityInstance actInst, Integer status, String message)
            throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.getDataAccess().setActivityInstanceStatus(actInst, status, message);
        } catch (DataAccessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).setActivityInstanceStatus(actInst, status, message);
            }
            else {
                throw ex;
            }
        } catch (SQLException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).setActivityInstanceStatus(actInst, status, message);
            }
            else {
                throw new DataAccessException("Failed to set activity instance status", ex);
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public void updateActivityInstanceEndTime(Long actInstId, Date endtime) throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.getDataAccess().updateActivityInstanceEndTime(actInstId, endtime);
        } catch (DataAccessException ex) {
                if (canRetryTransaction(ex)) {
                    transaction = (TransactionWrapper)initTransactionRetry(transaction);
                    ((ProcessExecutor)getTransactionRetrier()).updateActivityInstanceEndTime(actInstId, endtime);
                }
                else {
                    throw ex;
                }
        } catch (SQLException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).updateActivityInstanceEndTime(actInstId, endtime);
            }
            else {
                throw new DataAccessException("Failed to update activity end time", ex);
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public int countActivityInstances(Long procInstId, Long activityId) throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.getDataAccess().countActivityInstances(procInstId, activityId);
        } catch (DataAccessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).countActivityInstances(procInstId, activityId);
            }
            else {
                throw ex;
            }
        } catch (SQLException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).countActivityInstances(procInstId, activityId);
            }
            else {
                throw new DataAccessException("Failed to count activity instances", ex);
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public void createTransitionInstances(ProcessInstance processInstance, List transitions,
            Long fromActivityInstanceId) throws ProcessException, DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.createTransitionInstances(processInstance, transitions, fromActivityInstanceId);
        } finally {
            stopTransaction(transaction);
        }
    }

    public void determineCompletedTransitions(Long processInstanceId, List transitions)
            throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.getDataAccess().determineCompletedTransitions(processInstanceId, transitions);
        } catch (DataAccessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).determineCompletedTransitions(processInstanceId, transitions);
            }
            else {
                throw ex;
            }
        } catch (SQLException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).determineCompletedTransitions(processInstanceId, transitions);
            }
            else {
                throw new DataAccessException("Failed to determine completed transitions", ex);
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public void updateDocumentInfo(DocumentReference docRef, String documentType, String ownerType, Long ownerId,
            Integer statusCode, String statusMessage) throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.updateDocumentInfo(docRef, documentType, ownerType, ownerId, statusCode, statusMessage);
        } catch (DataAccessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).updateDocumentInfo(docRef, documentType, ownerType, ownerId, statusCode, statusMessage);
            }
            else {
                throw ex;
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public VariableInstance createVariableInstance(ProcessInstance pi, String varName, Object value)
            throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.createVariableInstance(pi, varName, value);
        } catch (DataAccessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).createVariableInstance(pi, varName, value);
            }
            else {
                throw ex;
            }
        } catch (SQLException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).createVariableInstance(pi, varName, value);
            }
            else {
                throw new DataAccessException("Failed to create variable instance", ex);
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public void updateVariableInstance(VariableInstance variableInstance, Package pkg) throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.getDataAccess().updateVariableInstance(variableInstance, pkg);
        } catch (DataAccessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).updateVariableInstance(variableInstance, pkg);
            }
            else {
                throw ex;
            }
        } catch (SQLException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).updateVariableInstance(variableInstance, pkg);
            }
            else {
                throw new DataAccessException("Failed to update variable instance", ex);
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public VariableInstance getVariableInstance(Long procInstId, String varName) throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.getDataAccess().getVariableInstance(procInstId, varName);
        } catch (DataAccessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).getVariableInstance(procInstId, varName);
            }
            else {
                throw ex;
            }
        } catch (SQLException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).getVariableInstance(procInstId, varName);
            }
            else {
                throw new DataAccessException("Failed to get variable instance", ex);
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public Document getDocument(DocumentReference docRef, boolean forUpdate) throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.getDocument(docRef, forUpdate);
        } catch (DataAccessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).getDocument(docRef, forUpdate);
            }
            else {
                throw ex;
            }
        } finally {
            if (!forUpdate)  // Do not release the locked "for update" document row
                stopTransaction(transaction);
        }
    }

    /**
     * Always goes to the database.
     */
    public Document loadDocument(DocumentReference docRef, boolean forUpdate) throws DataAccessException {
        TransactionWrapper transaction=null;
        try {
            transaction = startTransaction();
            return engineImpl.loadDocument(docRef, forUpdate);
        } catch (DataAccessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).loadDocument(docRef, forUpdate);
            }
            else {
                throw ex;
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public DocumentReference createDocument(String variableType, String ownerType, Long ownerId, Object docObj, Package pkg)
            throws DataAccessException {
        return createDocument(variableType, ownerType, ownerId, null, null, docObj, pkg);
    }

    public DocumentReference createDocument(String variableType, String ownerType, Long ownerId, Integer statusCode,
            String statusMessage, Object docObj, Package pkg) throws DataAccessException {
        return createDocument(variableType, ownerType, ownerId, statusCode, statusMessage, null, docObj, pkg);
    }

    public DocumentReference createDocument(String variableType, String ownerType, Long ownerId, Integer statusCode,
            String statusMessage, String path, Object docObj, Package pkg) throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.createDocument(variableType, ownerType, ownerId, statusCode, statusMessage, path, docObj, pkg);
        } catch (DataAccessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).createDocument(variableType, ownerType, ownerId, statusCode, statusMessage, path, docObj, pkg);
            }
            else {
                throw ex;
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public void updateDocumentContent(DocumentReference docRef, Object doc, Package pkg)
            throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.updateDocumentContent(docRef, doc, pkg);
        } catch (DataAccessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).updateDocumentContent(docRef, doc, pkg);
            }
            else {
                throw ex;
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public void addDocumentToCache(Document doc) {
        if (engineImpl.getDataAccess() instanceof EngineDataAccessCache) {
            ((EngineDataAccessCache)engineImpl.getDataAccess()).addDocumentToCache(doc);
        }
    }

    public void cancelEventWaitInstances(Long activityInstanceId) throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.cancelEventWaitInstances(activityInstanceId);
        } catch (DataAccessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).cancelEventWaitInstances(activityInstanceId);
            }
            else {
                throw ex;
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public boolean deleteInternalEvent(String eventName) throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.deleteInternalEvent(eventName);
        } catch (DataAccessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).deleteInternalEvent(eventName);
            }
            else {
                throw new DataAccessException("Failed to delete internal event" + eventName, ex);
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public EventWaitInstance createEventWaitInstance(Long procInstId, Long actInstId, String eventName,
            String compCode, boolean recurring, boolean notifyIfArrived, boolean reregister)
    throws DataAccessException, ProcessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.createEventWaitInstance(procInstId, actInstId,
                    eventName, compCode, recurring, notifyIfArrived, reregister);
        }
        catch (MdwException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).createEventWaitInstance(procInstId, actInstId, eventName, compCode, recurring, notifyIfArrived, reregister);
            }
            else {
                throw ex;
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public EventWaitInstance createEventWaitInstance(Long procInstId, Long actInstId, String eventName,
            String compCode, boolean recurring, boolean notifyIfArrived)
    throws DataAccessException, ProcessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.createEventWaitInstance(procInstId, actInstId, eventName, compCode, recurring, notifyIfArrived);
        }
        catch (MdwException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).createEventWaitInstance(procInstId, actInstId,
                        eventName, compCode, recurring, notifyIfArrived);
            }
            else {
                throw ex;
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public EventWaitInstance createEventWaitInstances(Long procInstId, Long actInstId, String[] eventNames,
            String[] wakeUpEventTypes, boolean[] eventOccurances, boolean notifyIfArrived, boolean reregister)
            throws DataAccessException, ProcessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.createEventWaitInstances(procInstId, actInstId, eventNames, wakeUpEventTypes,
                    eventOccurances, notifyIfArrived, reregister);
        }
        catch (MdwException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).createEventWaitInstances(procInstId, actInstId,
                        eventNames, wakeUpEventTypes, eventOccurances, notifyIfArrived, reregister);
            }
            else {
                throw ex;
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public void removeEventWaitForActivityInstance(Long activityInstanceId, String reason) throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.getDataAccess().removeEventWaitForActivityInstance(activityInstanceId, reason);
        } catch (DataAccessException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).removeEventWaitForActivityInstance(activityInstanceId, reason);
            }
            else {
                throw ex;
            }
        } catch (SQLException ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                ((ProcessExecutor)getTransactionRetrier()).removeEventWaitForActivityInstance(activityInstanceId, reason);
            }
            else {
                throw new DataAccessException("Failed to remove event wait for activity instance", ex);
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public Integer notifyProcess(String eventName, Long docId, String message, int delay)
            throws DataAccessException, EventException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.notifyProcess(eventName, docId, message, delay);
        } catch (DataAccessException | EventException ex){
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).notifyProcess(eventName, docId, message, delay);
            }
            else {
                throw ex;
            }
        } catch (SQLException ex){
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).notifyProcess(eventName, docId, message, delay);
            }
            else {
                throw new DataAccessException("Failed to notify process of event arrival", ex);
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public void sendDelayedInternalEvent(InternalEvent event, int delaySeconds, String msgid, boolean isUpdate)
        throws MdwException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.sendDelayedInternalEvent(event, delaySeconds, msgid, isUpdate);
        } finally {
            stopTransaction(transaction);
        }
    }

    public Response getSynchronousProcessResponse(Long procInstId, String varName, Package pkg)
            throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.getServiceProcessResponse(procInstId, varName, pkg);
        } catch (Exception ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).getSynchronousProcessResponse(procInstId, varName, pkg);
            }
            else {
                throw new DataAccessException("Failed to get value for variable " + varName, ex);
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    public Map getOutPutParameters(Long procInstId, Long procId) throws DataAccessException {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            return engineImpl.getOutputParameters(procInstId, procId);
        } catch (Exception ex) {
            if (canRetryTransaction(ex)) {
                transaction = (TransactionWrapper)initTransactionRetry(transaction);
                return ((ProcessExecutor)getTransactionRetrier()).getOutPutParameters(procInstId, procId);
            }
            else {
                throw new DataAccessException("Failed to get output parameters:" + procInstId, ex);
            }
        } finally {
            stopTransaction(transaction);
        }
    }

    /**
     * This method must be called within the same transaction scope (namely engine is already started
     */
    public Integer lockActivityInstance(Long actInstId) throws DataAccessException {
        try {
            if (!isInTransaction())
                throw new DataAccessException("Cannot lock activity instance without a transaction");
            return engineImpl.getDataAccess().lockActivityInstance(actInstId);
        } catch (SQLException ex) {
            throw new DataAccessException("Failed to lock activity instance", ex);
        }
    }

    /**
     * this method must be called within the same transaction scope (namely engine is already started
     */
    public Integer lockProcessInstance(Long procInstId) throws DataAccessException {
        try {
            if (!isInTransaction())
                throw new DataAccessException("Cannot lock activity instance without a transaction");
            return engineImpl.getDataAccess().lockProcessInstance(procInstId);
        } catch (SQLException ex) {
            throw new DataAccessException("Failed to lock process instance", ex);
        }
    }

    InternalMessenger getInternalMessenger() {
        return engineImpl.getInternalMessenger();
    }

    public int getPerformanceLevel() {
        return engineImpl.getDataAccess().getPerformanceLevel();
    }

    public boolean isInMemory() {
        return engineImpl.isInMemory();
    }

    public boolean isInService() {
        return engineImpl.isInService();
    }

    public DatabaseAccess getDatabaseAccess() throws SQLException {
        DatabaseAccess db = engineImpl.getDatabaseAccess();
        if (db == null)
            throw new SQLException("Engine database is not open");
        return db;
    }

    public TransactionWrapper startTransaction() throws DataAccessException {
        return engineImpl.getDataAccess().startTransaction();
    }

    public void stopTransaction(TransactionWrapper transaction) throws DataAccessException {
        engineImpl.getDataAccess().stopTransaction(transaction);
    }

    public void rollbackTransaction() {
        engineImpl.getDatabaseAccess().rollback();
    }

    private boolean isInTransaction() {
        try {
            return TransactionUtil.getInstance().isInTransaction();
        } catch (SystemException ex) {
            StandardLogger logger = LoggerUtil.getStandardLogger();
            logger.error("Fail to check if inside transaction - treated as not", ex);
            return false;
        }
    }

    /**
     * Notify registered ProcessMonitors.
     */
    public void notifyMonitors(ProcessInstance processInstance, WorkStatus.InternalLogMessage logMessage) {
        TransactionWrapper transaction = null;
        try {
            transaction = startTransaction();
            engineImpl.notifyMonitors(processInstance, logMessage);
        }
        catch (Exception ex) {
            // do not stop processing due to notification failure
            LoggerUtil.getStandardLogger().error(ex.getMessage(), ex);
        }
        finally {
            try {
                stopTransaction(transaction);
            }
            catch (DataAccessException ex) {
                LoggerUtil.getStandardLogger().error(ex.getMessage(), ex);
            }
        }
    }

    public boolean canRetryTransaction(Throwable th) {
        if (transactionRetryMax < 0)
            transactionRetryMax = PropertyManager.getIntegerProperty(PropertyNames.MDW_TRANSACTION_RETRY_MAX, 3);

        if (transactionRetryCount < transactionRetryMax) {
            if (engineImpl.getDatabaseAccess().isMySQL()) {
                if (th.getMessage() != null && th.getMessage().contains("try restarting transaction")) {
                    ProcessExecutorImpl.logger.warn("Encountered the following MySQL issue - will retry transaction (Attempt " + (transactionRetryCount+1) + " of " + transactionRetryMax + "): " + th.getMessage());
                    return true;
                }
                if (th.getCause() != null)
                    return canRetryTransaction(th.getCause());
            }
        }
        else {
            ProcessExecutorImpl.logger.error("Encountered the following issue - will NOT retry transaction (Max attempts reached): " + th.getMessage());
        }
        return false;
    }

    public Object getTransactionRetrier() {
        ProcessExecutor retrier = this;
        if (transactionRetryCount == 0) {
            retrier = new ProcessExecutor(engineImpl);
            retrier.setTransactionRetryCount(1);
        }
        else {
            retrier.setTransactionRetryCount(transactionRetryCount + 1);
        }

        return retrier;
    }

    public Object initTransactionRetry(TransactionWrapper transaction) throws DataAccessException {
        rollbackTransaction();
        stopTransaction(transaction);

        if (transactionRetryInterval < 0)
            transactionRetryInterval = PropertyManager.getIntegerProperty(PropertyNames.MDW_TRANSACTION_RETRY_INTERVAL, 1000);

        try {
            Thread.sleep(transactionRetryInterval);
        }
        catch (InterruptedException e) {
            // If interrupted, continue with transaction retry
        }
        return null;
    }

    public int getTransactionRetryCount() {
        return transactionRetryCount;
    }

    public void setTransactionRetryCount(int count) {
        transactionRetryCount = count;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy