com.ephesoft.dcma.workflows.service.impl.RestartBatchServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.ephesoft.dcma.workflows.service.impl.RestartBatchServiceImpl.java

Source

/********************************************************************************* 
* Ephesoft is a Intelligent Document Capture and Mailroom Automation program 
* developed by Ephesoft, Inc. Copyright (C) 2015 Ephesoft Inc. 
* 
* This program is free software; you can redistribute it and/or modify it under 
* the terms of the GNU Affero General Public License version 3 as published by the 
* Free Software Foundation with the addition of the following permission added 
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK 
* IN WHICH THE COPYRIGHT IS OWNED BY EPHESOFT, EPHESOFT DISCLAIMS THE WARRANTY 
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. 
* 
* This program is distributed in the hope that it will be useful, but WITHOUT 
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
* FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
* details. 
* 
* You should have received a copy of the GNU Affero General Public License along with 
* this program; if not, see http://www.gnu.org/licenses or write to the Free 
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
* 02110-1301 USA. 
* 
* You can contact Ephesoft, Inc. headquarters at 111 Academy Way, 
* Irvine, CA 92617, USA. or at email address info@ephesoft.com. 
* 
* The interactive user interfaces in modified source and object code versions 
* of this program must display Appropriate Legal Notices, as required under 
* Section 5 of the GNU Affero General Public License version 3. 
* 
* In accordance with Section 7(b) of the GNU Affero General Public License version 3, 
* these Appropriate Legal Notices must retain the display of the "Ephesoft" logo. 
* If the display of the logo is not reasonably feasible for 
* technical reasons, the Appropriate Legal Notices must display the words 
* "Powered by Ephesoft". 
********************************************************************************/

package com.ephesoft.dcma.workflows.service.impl;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Properties;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;

import com.ephesoft.dcma.batch.service.BatchSchemaService;
import com.ephesoft.dcma.batch.service.EphesoftContext;
import com.ephesoft.dcma.batch.service.ImportBatchService;
import com.ephesoft.dcma.core.common.BatchInstanceStatus;
import com.ephesoft.dcma.core.component.ICommonConstants;
import com.ephesoft.dcma.core.exception.DCMAApplicationException;
import com.ephesoft.dcma.da.domain.BatchClass;
import com.ephesoft.dcma.da.domain.BatchClassModule;
import com.ephesoft.dcma.da.domain.BatchClassPlugin;
import com.ephesoft.dcma.da.domain.BatchInstance;
import com.ephesoft.dcma.da.service.BatchClassModuleService;
import com.ephesoft.dcma.da.service.BatchClassService;
import com.ephesoft.dcma.da.service.BatchInstanceService;
import com.ephesoft.dcma.da.service.ServerRegistryService;
import com.ephesoft.dcma.util.BackUpFileService;
import com.ephesoft.dcma.util.EphesoftStringUtil;
import com.ephesoft.dcma.util.FileUtils;
import com.ephesoft.dcma.util.logger.EphesoftLogger;
import com.ephesoft.dcma.util.logger.EphesoftLoggerFactory;
import com.ephesoft.dcma.workflows.client.EphesoftWebServiceClient;
import com.ephesoft.dcma.workflows.constant.WorkflowConstants;
import com.ephesoft.dcma.workflows.service.RestartBatchService;
import com.ephesoft.dcma.workflows.service.WorkflowService;
import com.ephesoft.dcma.workflows.service.engine.EngineService;
import com.ephesoft.dcma.workflows.util.RestartingBatchDetails;

/**
 * This class represents service to restart batch.
 * 
 * @author Ephesoft
 * 
 *         <b>created on</b> Oct 21, 2014 <br/>
 * @version $LastChangedDate:$ <br/>
 *          $LastChangedRevision:$ <br/>
 */
public class RestartBatchServiceImpl implements RestartBatchService {

    /**
     * {@link BatchClassService} Instance of batch class service.
     */
    @Autowired
    private BatchClassService batchClassService;

    /**
     * {@link BatchInstanceService} Instance of batch instance service.
     */
    @Autowired
    private BatchInstanceService batchInstanceService;

    /**
     * {@link ServerRegistryService} Instance of registry service.
     */
    @Autowired
    private ServerRegistryService registryService;

    /**
     * {@link EphesoftWebServiceClient} Instance of Web service client.
     */
    @Autowired
    private EphesoftWebServiceClient ephesoftWebServiceClient;

    /**
     * {@link BatchClassModuleService} Instance of batch class module service.
     */
    @Autowired
    private BatchClassModuleService batchClassModuleService;

    /**
     * {@link BatchSchemaService} Instance of batch schema service.
     */
    @Autowired
    private BatchSchemaService batchSchemaService;

    /**
     * {@link ImportBatchService} Instance of import batch service.
     */
    @Autowired
    private ImportBatchService importBatchService;

    /**
     * {@link EngineService} Instance of engine service.
     */
    @Autowired
    private EngineService engineService;

    /**
     * {@link WorkflowService} Instance of workflow service.
     */
    @Autowired
    private WorkflowService workflowService;

    /**
     * {@link EphesoftLogger} Instance of Logger.
     */
    private static final EphesoftLogger LOGGER = EphesoftLoggerFactory.getLogger(RestartBatchServiceImpl.class);

    @Override
    public boolean restartBatchInstanceWithoutCleaning(final String batchInstanceIdentifier,
            final String moduleName) {
        boolean result = false;
        try {
            result = restartBatch(batchInstanceIdentifier, moduleName, false, false, false);
        } catch (DCMAApplicationException dcmaApplicationException) {
            // Do Nothing.
        }
        return result;
    }

    @Override
    public boolean restartBatchInstance(String batchInstanceIdentifier, String moduleName, boolean throwException,
            boolean resumeBatchInstance) throws DCMAApplicationException {
        boolean result = false;
        result = restartBatch(batchInstanceIdentifier, moduleName, throwException, true, resumeBatchInstance);
        return result;
    }

    @Override
    public String getBatchLastExecutedModule(final BatchInstance batchInstance) {
        String moduleName;
        final String executedModules = batchInstance.getExecutedModules();
        if (EphesoftStringUtil.isNullOrEmpty(executedModules)) {
            moduleName = null;
        } else {
            final String[] splitString = EphesoftStringUtil.splitString(executedModules,
                    String.valueOf(ICommonConstants.EXECUTED_MODULE_ID_SEPARATOR));
            if (null == splitString) {
                moduleName = null;
            } else {
                final long moduleId = Long.valueOf(splitString[splitString.length - 1]);
                BatchClass loadedBatchClass = batchInstanceService
                        .getLoadedBatchClassByBatchIdentifier(batchInstance);
                if (null == loadedBatchClass) {
                    moduleName = null;
                } else {
                    moduleName = batchClassModuleService.getModuleNameByModuleId(loadedBatchClass, moduleId);
                }
            }
        }
        return moduleName;
    }

    /**
     * Restarts a batch instance.
     * 
     * @param batchInstanceIdentifier {@link String}
     * @param moduleName {@link String}
     * @param throwException boolean
     * @param isClean boolean
     * @param resumeBatchInstance boolean
     * @return boolean
     * @throws DCMAApplicationException
     */
    private boolean restartBatch(final String batchInstanceIdentifier, final String moduleName,
            final boolean throwException, final boolean isClean, final boolean resumeBatchInstance)
            throws DCMAApplicationException {
        boolean result = true;
        LOGGER.info("Restarting batch instance: ", batchInstanceIdentifier);
        BatchInstance batchInstance = batchInstanceService.getBatchInstanceByIdentifier(batchInstanceIdentifier);
        if (null != batchInstance) {
            if (!EphesoftStringUtil.isNullOrEmpty(batchInstance.getReviewUserName())
                    || !EphesoftStringUtil.isNullOrEmpty(batchInstance.getValidationUserName())) {
                clearReviewValidationUsers(batchInstance, moduleName);

            }
            try {
                resetBatchClassAndPriority(batchInstance);
                final String batchInstanceExecutingServer = batchInstance.getExecutingServer();
                boolean sameServer = engineService.isSameServer(batchInstanceExecutingServer);
                List<BatchClassModule> batchClassModulesInOrder = getBatchClassModules(batchInstance);
                BatchClassModule prescursorBatchClassModule;
                if (CollectionUtils.isNotEmpty(batchClassModulesInOrder)) {
                    prescursorBatchClassModule = batchClassModulesInOrder.get(0);
                } else {
                    prescursorBatchClassModule = null;
                }

                // if case is for remote web service or other server starting it.
                if (!sameServer && null != batchInstanceExecutingServer) {
                    result = restartBatchRemotely(batchInstanceIdentifier, moduleName, throwException,
                            batchInstance, batchInstanceExecutingServer, prescursorBatchClassModule);
                } else {
                    RestartingBatchDetails restartingBatchDetails = new RestartingBatchDetails();
                    restartingBatchDetails.setModuleName(moduleName);
                    restartingBatchDetails.setBatchClassModulesInOrder(batchClassModulesInOrder);
                    restartingBatchDetails.setBatchInstance(batchInstance);
                    restartingBatchDetails.setBatchInstanceIdentifier(batchInstanceIdentifier);
                    restartingBatchDetails.setPrescursorBatchClassModule(prescursorBatchClassModule);
                    result = restartBatchInternally(restartingBatchDetails, throwException, isClean,
                            resumeBatchInstance);
                }
            } catch (Exception exception) {
                result = false;
                LOGGER.error(exception, "Batch: ", batchInstanceIdentifier,
                        " could not be restarted and went into error state due to: ", exception.getMessage());

                // update the batch instance to ERROR state.
                if (throwException) {
                    throw new DCMAApplicationException(exception.getMessage());
                }
            }
        }
        return result;

    }

    private void clearReviewValidationUsers(BatchInstance batchInstance, String moduleName) {
        List<BatchClassModule> moduleList = batchInstance.getBatchClass().getBatchClassModuleInOrder();
        BatchClassModule restartModule = batchInstance.getBatchClass().getBatchClassModuleByDesc(moduleName);
        BatchClassModule lastExecutedModule = batchInstance.getBatchClass()
                .getBatchClassModuleByDesc(getBatchLastExecutedModule(batchInstance));

        for (BatchClassModule batchClassModule : moduleList) {
            if (batchClassModule.compareTo(lastExecutedModule) <= 0
                    && batchClassModule.compareTo(restartModule) >= 0) {
                for (BatchClassPlugin batchClassPlugin : batchClassModule.getBatchClassPlugins()) {
                    if (batchClassPlugin.getPlugin().getPluginName().equalsIgnoreCase("REVIEW_DOCUMENT")) {
                        batchInstance.setReviewUserName(null);
                    }
                    if (batchClassPlugin.getPlugin().getPluginName().equalsIgnoreCase("VALIDATE_DOCUMENT")) {
                        batchInstance.setValidationUserName(null);
                    }
                }
            }
        }
        batchInstanceService.updateBatchInstance(batchInstance);
    }

    /**
     * Gets modules for a batch class.
     * 
     * @param batchInstance {@link BatchInstance}
     * @return {@link List}<{@link BatchClassModule}>
     */
    private List<BatchClassModule> getBatchClassModules(final BatchInstance batchInstance) {
        List<BatchClassModule> batchClassModulesInOrder = null;

        // #5211: Batch class modules list is fetched from loaded batch class to avoid lazy initialization exception.
        BatchClass batchClassUpdated = batchInstanceService.getLoadedBatchClassByBatchIdentifier(batchInstance);
        if (null != batchClassUpdated) {
            batchClassModulesInOrder = batchClassUpdated.getBatchClassModuleInOrder();
        }
        return batchClassModulesInOrder;
    }

    /**
     * Restarts a batch instance on the current server.
     * 
     * @param restartingBatchDetails {@link RestartingBatchDetails}
     * @param throwException boolean
     * @param isClean boolean
     * @param resumeBatchInstance boolean
     * @return boolean
     * @throws DCMAApplicationException
     */
    private boolean restartBatchInternally(final RestartingBatchDetails restartingBatchDetails,
            final boolean throwException, final boolean isClean, final boolean resumeBatchInstance)
            throws DCMAApplicationException {
        boolean result;
        String batchInstanceIdentifier = restartingBatchDetails.getBatchInstanceIdentifier();
        final BatchInstance batchInstance = restartingBatchDetails.getBatchInstance();

        // #5211: To stop batches stuck at RESTART_IN_PROGRESS
        if (isClean) {
            engineService.cleanBatchResources(batchInstanceIdentifier);
        }
        engineService.deleteProcessInstanceByBatchInstance(batchInstance, false);
        batchSchemaService.removeBatch(batchInstanceIdentifier);
        verifyRestartForWorkFlowContinue(batchInstanceIdentifier, throwException);

        // batchClassModulesInOrder same server restarting it or not started yet.
        String updatedExecutedModules = updateBatchInstance(restartingBatchDetails);
        if (resumeBatchInstance) {
            String moduleWorkFlowName = workflowService.getWorkflowNameByModuleName(
                    restartingBatchDetails.getModuleName(), restartingBatchDetails.getBatchClassModulesInOrder());
            workflowService.startWorkflow(restartingBatchDetails.getBatchInstance().getBatchInstanceID(),
                    moduleWorkFlowName);
        } else {
            batchInstance.setStatus(BatchInstanceStatus.READY);
        }
        batchInstance.setCurrentUser(null);
        batchInstance.setServerIP(null);
        batchInstance.setExecutingServer(null);
        batchInstance.setExecutedModules(updatedExecutedModules);
        batchInstanceService.updateBatchInstance(batchInstance);
        result = true;
        return result;
    }

    /**
     * Verify if restart is valid.
     * 
     * @param batchInstanceIdentifier {@link String}
     * @param throwException boolean
     * @throws DCMAApplicationException
     */
    private void verifyRestartForWorkFlowContinue(final String batchInstanceIdentifier,
            final boolean throwException) throws DCMAApplicationException {
        String activeModule = workflowService.getActiveModuleName(batchInstanceIdentifier);
        if (null == activeModule) {
            activeModule = workflowService.getErrorBatchLastExecutedModule(batchInstanceIdentifier);
        }
        if (!EphesoftStringUtil.isNullOrEmpty(activeModule)
                && activeModule.contains(WorkflowConstants.WORKFLOW_CONTINUE_CHECK)) {
            LOGGER.error("Error in restarting batch instance : ", batchInstanceIdentifier);
            if (throwException) {
                throw new DCMAApplicationException(WorkflowConstants.RESTART_ERROR_MESSAGE);
            }
        }
    }

    /**
     * Updates batch instance for making it ready for restart.
     * 
     * @param restartingBatchDetails {@link RestartingBatchDetails}
     * @return {@link String}
     * @throws DCMAApplicationException
     */
    private String updateBatchInstance(final RestartingBatchDetails restartingBatchDetails)
            throws DCMAApplicationException {
        String batchInstanceIdentifier = restartingBatchDetails.getBatchInstanceIdentifier();
        String moduleName = restartingBatchDetails.getModuleName();
        final BatchInstance batchInstance = restartingBatchDetails.getBatchInstance();
        final List<BatchClassModule> batchClassModulesInOrder = restartingBatchDetails
                .getBatchClassModulesInOrder();
        BatchClassModule precursorBatchClassModule = restartingBatchDetails.getPrescursorBatchClassModule();

        // Getting workflow name for the module to be restarted with.
        String moduleWorkFlowName = workflowService.getWorkflowNameByModuleName(moduleName,
                batchClassModulesInOrder);
        if (null == moduleWorkFlowName && null != batchInstance.getRemoteBatchInstance()) {
            moduleWorkFlowName = batchInstance.getRemoteBatchInstance().getSourceModule();
        }
        if (EphesoftStringUtil.isNullOrEmpty(moduleWorkFlowName)) {
            deleteBatchFolder(batchInstance);
            importBatchService.removeFolders(batchInstance);
            if (null != precursorBatchClassModule) {
                moduleWorkFlowName = precursorBatchClassModule.getWorkflowName();
            }
        } else {
            Properties properties = fetchConfig(BackUpFileService.BACKUP_PROPERTY_FILE);
            try {
                importBatchService.updateBatchFolders(properties, batchInstance, moduleWorkFlowName,
                        batchSchemaService.isZipSwitchOn(), batchClassModulesInOrder);
            } catch (Exception updateBatchFolderException) {
                String errorMessage = EphesoftStringUtil.concatenate(
                        "Error while updating batch folders for the batch: ", batchInstanceIdentifier,
                        " while restarting it.");
                LOGGER.error(errorMessage);
                throw new DCMAApplicationException(errorMessage, updateBatchFolderException);
            }
        }
        String executedModules = updateExecutedModules(batchInstanceIdentifier, moduleWorkFlowName, batchInstance);
        return executedModules;
    }

    /**
     * Restart batch remotely on another server.
     * 
     * @param batchInstanceIdentifier {@link String}
     * @param moduleName {@link String}
     * @param throwException boolean
     * @param batchInstance {@link BatchInstance}
     * @param batchInstanceExecutingServer {@link String}
     * @param prescursorBatchClassModule {@link BatchClassModule}
     * @return boolean
     * @throws DCMAApplicationException {@link DCMAApplicationException}
     */
    private boolean restartBatchRemotely(final String batchInstanceIdentifier, String moduleName,
            final boolean throwException, final BatchInstance batchInstance,
            final String batchInstanceExecutingServer, final BatchClassModule prescursorBatchClassModule)
            throws DCMAApplicationException {
        boolean result;
        if (moduleName == null) {
            if (null != batchInstance.getRemoteBatchInstance()) {
                moduleName = batchInstance.getRemoteBatchInstance().getSourceModule();
            } else if (null != prescursorBatchClassModule) {
                moduleName = prescursorBatchClassModule.getModule().getName();
            }
        }
        if (EphesoftContext.getCurrent().isSecure()) {
            result = ephesoftWebServiceClient.restartBatchInstance(
                    EphesoftStringUtil.concatenate(ICommonConstants.HTTPS_SLASH, batchInstanceExecutingServer,
                            ICommonConstants.FORWARD_SLASH, ICommonConstants.WEB_SERVICE),
                    batchInstanceIdentifier, moduleName, String.valueOf(throwException));
        } else {
            result = ephesoftWebServiceClient.restartBatchInstance(
                    EphesoftStringUtil.concatenate(ICommonConstants.HTTP_SLASH, batchInstanceExecutingServer,
                            ICommonConstants.FORWARD_SLASH, ICommonConstants.WEB_SERVICE),
                    batchInstanceIdentifier, moduleName, String.valueOf(throwException));
        }
        return result;
    }

    /**
     * Update executed modules for restart.
     * 
     * @param batchInstanceIdentifier {@link String}
     * @param moduleWorkflowName {@link String}
     * @param batchInstance {@link BatchInstance}
     * @return {@link String}
     */
    private String updateExecutedModules(final String batchInstanceIdentifier, final String moduleWorkflowName,
            final BatchInstance batchInstance) {
        String editedExecutedModules;
        if (EphesoftStringUtil.isNullOrEmpty(moduleWorkflowName)) {
            editedExecutedModules = ICommonConstants.EMPTY_STRING;
        } else {
            String executedModules = batchInstance.getExecutedModules();
            if (EphesoftStringUtil.isNullOrEmpty(executedModules)) {
                editedExecutedModules = ICommonConstants.EMPTY_STRING;
            } else {
                BatchClass batchClass = batchInstanceService.getLoadedBatchClassByBatchIdentifier(batchInstance);
                if (null == batchClass) {
                    editedExecutedModules = ICommonConstants.EMPTY_STRING;
                } else {
                    String batchClassIdentifier = batchClass.getIdentifier();
                    long moduleId = batchClassModuleService.getModuleIdByWorkflowName(batchClassIdentifier,
                            moduleWorkflowName);
                    editedExecutedModules = editExecutedModules(moduleWorkflowName, executedModules, moduleId);
                }
            }
        }
        LOGGER.debug("Updated executed modules for restarting batch: ", batchInstanceIdentifier, " is: ",
                editedExecutedModules);
        return editedExecutedModules;
    }

    /**
     * Edit executed modules for the restarting batches.
     * 
     * @param moduleName {@link String}
     * @param executedModules {@link String}
     * @param batchClassModuleByWorkflowName {@link BatchClassModule}
     * @return {@link String}
     */
    private String editExecutedModules(final String moduleName, final String executedModules, final long moduleId) {

        // Updating executed modules just till the module id(and separator) of the module restarted with.
        String editedExecutedModules;
        if (0 != moduleId) {
            LOGGER.debug("Module name: ", moduleName, " with module id: ", moduleId);
            int index = executedModules.indexOf(String.valueOf(moduleId));
            if (index > -1) {
                editedExecutedModules = executedModules.substring(0, index + 2);
            } else {
                editedExecutedModules = ICommonConstants.EMPTY_STRING;
            }
        } else {
            editedExecutedModules = ICommonConstants.EMPTY_STRING;
        }
        return editedExecutedModules;
    }

    /**
     * Deletes a batch instance.
     * 
     * @param batchInstance {@link BatchInstance}
     */
    private void deleteBatchFolder(final BatchInstance batchInstance) {
        String batchFilePath = EphesoftStringUtil.concatenate(batchInstance.getLocalFolder(), File.separator,
                batchInstance.getIdentifier());
        String batchInstanceIdentifier = batchInstance.getIdentifier();
        if (EphesoftStringUtil.isNullOrEmpty(batchFilePath)) {
            LOGGER.debug("Batch file path for batch: ", batchInstanceIdentifier, " for deleting its folders, is: ",
                    batchFilePath);
            File batchInstanceFolder = new File(batchFilePath);
            if (batchInstanceFolder.exists()) {
                FileUtils.deleteDirectoryAndContentsRecursive(batchInstanceFolder);
            }
        }
        LOGGER.info("Batch folder deleted successfully for ", batchInstanceIdentifier);
    }

    /**
     * Resets batch class for a batch instance.
     * 
     * @param batchInstance {@link BatchInstance}
     */
    private void resetBatchClassAndPriority(final BatchInstance batchInstance) {
        String batchInstanceIdentifier = batchInstance.getIdentifier();
        LOGGER.trace("Entering method to reset batch class for batch instance: ", batchInstanceIdentifier);
        BatchClass oldBatchClass = batchInstance.getBatchClass();

        // Reverted change for batch instance priority with changed priority of batch class.
        if (null != oldBatchClass) {
            String oldBatchClassIdentifier = oldBatchClass.getIdentifier();
            BatchClass newBatchClass = batchClassService.getBatchClassbyName(oldBatchClass.getName());
            String newBatchClassIdentifier = newBatchClass.getIdentifier();
            LOGGER.debug("New batch class identifier for batch instance: ", batchInstanceIdentifier, "is: ",
                    newBatchClassIdentifier);
            if (!EphesoftStringUtil.isNullOrEmpty(newBatchClassIdentifier)
                    && !newBatchClassIdentifier.equals(oldBatchClassIdentifier)) {
                batchInstance.setBatchClass(newBatchClass);
            }
            batchInstanceService.updateBatchInstance(batchInstance);
        }
    }

    /**
     * Fetches configuration for back up property service.
     * 
     * @param filePath {@link String}
     * @return {@link Properties}
     */
    private Properties fetchConfig(final String filePath) {
        ClassPathResource classPathResource = new ClassPathResource(filePath);
        Properties properties = new Properties();
        InputStream input = null;
        try {
            input = classPathResource.getInputStream();
            properties.load(input);
        } catch (IOException ioException) {
            LOGGER.error("Cannot open and load backUpService properties file.", ioException);
        } finally {
            try {
                if (null != input)
                    input.close();
            } catch (IOException ioException2) {
                LOGGER.error("Cannot close backUpService properties file.", ioException2);
            }
        }
        return properties;
    }

}