com.clustercontrol.jobmanagement.factory.JobSessionNodeImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.clustercontrol.jobmanagement.factory.JobSessionNodeImpl.java

Source

/*
    
Copyright (C) 2012 NTT DATA Corporation
    
This program is free software; you can redistribute it and/or
Modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, version 2.
    
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 General Public License for more details.
    
 */

package com.clustercontrol.jobmanagement.factory;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.persistence.EntityExistsException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.clustercontrol.bean.EndStatusConstant;
import com.clustercontrol.bean.HinemosModuleConstant;
import com.clustercontrol.bean.JobApprovalStatusConstant;
import com.clustercontrol.bean.StatusConstant;
import com.clustercontrol.commons.util.HinemosEntityManager;
import com.clustercontrol.commons.util.JpaTransactionManager;
import com.clustercontrol.fault.FacilityNotFound;
import com.clustercontrol.fault.HinemosUnknown;
import com.clustercontrol.fault.InvalidApprovalStatus;
import com.clustercontrol.fault.InvalidRole;
import com.clustercontrol.fault.JobInfoNotFound;
import com.clustercontrol.fault.JobMasterNotFound;
import com.clustercontrol.hinemosagent.bean.AgentInfo;
import com.clustercontrol.hinemosagent.util.AgentConnectUtil;
import com.clustercontrol.jobmanagement.bean.CommandConstant;
import com.clustercontrol.jobmanagement.bean.CommandStopTypeConstant;
import com.clustercontrol.jobmanagement.bean.CommandTypeConstant;
import com.clustercontrol.jobmanagement.bean.DelayNotifyConstant;
import com.clustercontrol.jobmanagement.bean.JobApprovalInfo;
import com.clustercontrol.jobmanagement.bean.JobConstant;
import com.clustercontrol.jobmanagement.bean.JobEnvVariableInfo;
import com.clustercontrol.jobmanagement.bean.JobParamTypeConstant;
import com.clustercontrol.jobmanagement.bean.ProcessingMethodConstant;
import com.clustercontrol.jobmanagement.bean.RunInstructionInfo;
import com.clustercontrol.jobmanagement.bean.RunResultInfo;
import com.clustercontrol.jobmanagement.bean.RunStatusConstant;
import com.clustercontrol.jobmanagement.model.JobCommandParamInfoEntity;
import com.clustercontrol.jobmanagement.model.JobEnvVariableInfoEntity;
import com.clustercontrol.jobmanagement.model.JobInfoEntity;
import com.clustercontrol.jobmanagement.model.JobParamInfoEntity;
import com.clustercontrol.jobmanagement.model.JobSessionJobEntity;
import com.clustercontrol.jobmanagement.model.JobSessionNodeEntity;
import com.clustercontrol.jobmanagement.model.JobSessionNodeEntityPK;
import com.clustercontrol.jobmanagement.util.FromRunningAfterCommitCallback;
import com.clustercontrol.jobmanagement.util.JobMultiplicityCache;
import com.clustercontrol.jobmanagement.util.MonitorJobWorker;
import com.clustercontrol.jobmanagement.util.ParameterUtil;
import com.clustercontrol.jobmanagement.util.QueryUtil;
import com.clustercontrol.jobmanagement.util.RunHistoryUtil;
import com.clustercontrol.jobmanagement.util.SendApprovalMail;
import com.clustercontrol.jobmanagement.util.SendTopic;
import com.clustercontrol.jobmanagement.util.ToRunningAfterCommitCallback;
import com.clustercontrol.maintenance.util.HinemosPropertyUtil;
import com.clustercontrol.repository.factory.NodeProperty;
import com.clustercontrol.util.HinemosTime;
import com.clustercontrol.util.MessageConstant;
import com.clustercontrol.util.Messages;

public class JobSessionNodeImpl {
    /** ? */
    private static Log m_log = LogFactory.getLog(JobSessionNodeImpl.class);

    /**
     * ?????
     *
     * @param sessionId ID
     * @param jobId ID
     * @param facilityId ID
     * @return true?????false??
     * @throws JobInfoNotFound
     * @throws InvalidRole
     */
    public boolean startNode(String sessionId, String jobunitId, String jobId) throws JobInfoNotFound, InvalidRole {
        m_log.debug("startNode() : sessionId=" + sessionId + ", jobId=" + jobId);

        //ID?ID???
        JobSessionJobEntity sessionJob = QueryUtil.getJobSessionJobPK(sessionId, jobunitId, jobId);
        Collection<JobSessionNodeEntity> jobSessionNodeList = sessionJob.getJobSessionNodeEntities();
        if (jobSessionNodeList == null || jobSessionNodeList.size() == 0) {
            //????
            try {
                new JobSessionJobImpl().endJob(sessionId, jobunitId, jobId, null, true);
            } catch (HinemosUnknown e) {
                m_log.warn("startNode() : no node. " + e.getMessage(), e);
            } catch (FacilityNotFound e) {
                m_log.warn("startNode() : no node. " + e.getMessage(), e);
            }
            return false;
        }

        //???????
        if (checkAllNodeEnd(sessionJob)) {
            return true;
        }

        //???????
        JobInfoEntity job = sessionJob.getJobInfoEntity();
        if (job.getProcessMode() == ProcessingMethodConstant.TYPE_RETRY) {
            //?????
            for (JobSessionNodeEntity sessionNode : jobSessionNodeList) {
                // ??(?)??????????????
                if (sessionNode.getStatus() == StatusConstant.TYPE_RUNNING
                        || sessionNode.getStatus() == StatusConstant.TYPE_STOPPING) {
                    return false;
                }
            }
        }

        ArrayList<JobSessionNodeEntity> orderedNodeList = new ArrayList<JobSessionNodeEntity>();
        ArrayList<String> validNodeList = AgentConnectUtil.getValidAgent();
        ArrayList<JobSessionNodeEntity> invalidNodeList = new ArrayList<JobSessionNodeEntity>();

        // ???????????
        for (JobSessionNodeEntity sessionNode : jobSessionNodeList) {
            if (validNodeList.contains(sessionNode.getId().getFacilityId())) {
                orderedNodeList.add(sessionNode);
            } else {
                invalidNodeList.add(sessionNode);
            }
        }

        // ????
        Collections.sort(orderedNodeList, new JobPriorityComparator());
        Collections.sort(invalidNodeList, new JobPriorityComparator());

        // ????????
        orderedNodeList.addAll(invalidNodeList);

        if (m_log.isDebugEnabled()) {
            StringBuilder str = new StringBuilder();
            for (JobSessionNodeEntity sessionNode : orderedNodeList) {
                str.append(sessionNode.getNodeName()).append(" -> ");
            }
            m_log.debug("orderedNodeList: " + str);
        }

        for (JobSessionNodeEntity sessionNode : orderedNodeList) {
            if (checkMultiplicity(sessionNode)) {
                JpaTransactionManager jtm = new JpaTransactionManager();
                jtm.addCallback(new ToRunningAfterCommitCallback(sessionNode.getId()));
                if (job.getProcessMode() == ProcessingMethodConstant.TYPE_RETRY) {
                    break;
                }
            }
        }
        return false;
    }

    private boolean checkMultiplicity(JobSessionNodeEntity sessionNode) {
        boolean startFlag = false;
        String facilityId = sessionNode.getId().getFacilityId();
        String sessionId = sessionNode.getId().getSessionId();
        String jobunitId = sessionNode.getId().getJobunitId();
        String jobId = sessionNode.getId().getJobId();
        if (sessionNode.getStatus() != StatusConstant.TYPE_WAIT) {
            return false;
        }
        if (JobMultiplicityCache.isRunNow(facilityId)) {
            return true;
        }
        try {
            JobSessionJobEntity sessionJob = QueryUtil.getJobSessionJobPK(sessionId, jobunitId, jobId);

            if (sessionJob.getJobInfoEntity().getMultiplicityNotify() == null) {
                // ???????
                m_log.info("multiplicity notify is null");
                return false;
            }

            // ????????
            m_log.debug("checkMultiplicity " + sessionJob.getJobInfoEntity().getMultiplicityNotify());
            if (sessionJob.getJobInfoEntity().getMultiplicityNotify().booleanValue()) {
                //?
                new Notice().multiplicityNotify(sessionId, jobunitId, jobId,
                        sessionJob.getJobInfoEntity().getMultiplicityOperation());
            }

            // ??????????????
            int status = sessionJob.getJobInfoEntity().getMultiplicityOperation();
            switch (status) {
            case StatusConstant.TYPE_WAIT:
                startFlag = true;
                break;
            case StatusConstant.TYPE_END:
                //??
                startFlag = false;
                sessionNode.setStatus(StatusConstant.TYPE_END);
                sessionNode.setEndValue(sessionJob.getJobInfoEntity().getMultiplicityEndValue());
                setMessage(sessionNode, MessageConstant.MESSAGE_EXCEEDED_MULTIPLICITY_OF_JOBS.getMessage());

                if (checkAllNodeEnd(sessionJob)) {
                    try {
                        new JobSessionJobImpl().endJob(sessionId, jobunitId, jobId, sessionNode.getResult(), true);
                    } catch (HinemosUnknown e) {
                        m_log.warn("wait2running END " + e.getMessage(), e);
                    } catch (FacilityNotFound e) {
                        m_log.warn("wait2running END " + e.getMessage(), e);
                    }
                }
                break;
            default:
                m_log.warn("wait2running " + status + " is unknown status");
                startFlag = true; // ?????
            }
        } catch (InvalidRole e) {
            m_log.warn("wait2running " + e.getMessage());
            startFlag = true; // ????
        } catch (JobInfoNotFound e) {
            m_log.warn("wait2running " + e.getMessage());
            startFlag = true; // ????
        }
        return startFlag;
    }

    /**
     * ????????
     * JobMultiplicityCache.kick()??????
     *
     * @param sessionId
     * @param jobunitId
     * @param jobId
     * @param facilityId
     * @return 0:?1:??????-1:???
     * @throws JobInfoNotFound
     */
    public int wait2running(JobSessionNodeEntityPK pk) {
        int startCommand = -1;

        String sessionId = pk.getSessionId();
        String jobunitId = pk.getJobunitId();
        String jobId = pk.getJobId();
        String facilityId = pk.getFacilityId();

        JobSessionNodeEntity sessionNode = null;
        try {
            sessionNode = QueryUtil.getJobSessionNodePK(sessionId, jobunitId, jobId, facilityId);
        } catch (JobInfoNotFound e) {
            m_log.warn("wait2running " + e.getMessage());
            return -1;
        }

        //??????
        if (sessionNode.getStatus() != StatusConstant.TYPE_WAIT) {
            return -1;
        }

        JobSessionJobEntity sessionJobEntity = null;
        try {
            sessionJobEntity = QueryUtil.getJobSessionJobPK(sessionId, jobunitId, jobId);
        } catch (JobInfoNotFound e) {
            m_log.warn("wait2running " + e.getMessage());
            return -1;
        } catch (InvalidRole e) {
            m_log.warn("wait2running " + e.getMessage());
            return -1;
        }

        //???????
        //waitQueue???false ?
        if (sessionJobEntity.getStatus() != StatusConstant.TYPE_RUNNING) {
            m_log.info("wait2running job detail is not running " + sessionNode.getId().getFacilityId() + ","
                    + sessionNode.getId().getSessionId() + "," + sessionNode.getId().getJobunitId() + ","
                    + sessionNode.getId().getJobId() + ", status is "
                    + StatusConstant.typeToMessageCode(sessionJobEntity.getStatus()));

            return 1;
        }

        //??
        m_log.info(
                "wait2running " + sessionNode.getId().getFacilityId() + "," + sessionNode.getId().getSessionId());
        sessionNode.setStatus(StatusConstant.TYPE_RUNNING);
        if (sessionJobEntity.getJobInfoEntity().getJobType() == JobConstant.TYPE_APPROVALJOB) {
            sessionNode.setApprovalStatus(JobApprovalStatusConstant.TYPE_PENDING);
        }
        if (sessionJobEntity.getJobInfoEntity().getJobType() != JobConstant.TYPE_MONITORJOB
                && sessionJobEntity.getJobInfoEntity().getJobType() != JobConstant.TYPE_APPROVALJOB) {
            setMessage(sessionNode, MessageConstant.WAIT_AGENT_RESPONSE.getMessage());
        }

        try {
            //Topic??
            m_log.debug("startNode() : send RunInstructionInfo() : " + "sessionId=" + sessionId + ", jobId=" + jobId
                    + ", facilityId=" + sessionNode.getId().getFacilityId());
            runJobSessionNode(sessionId, jobunitId, jobId, sessionNode.getId().getFacilityId());
            startCommand = 0;
        } catch (Exception e) {
            m_log.warn("startNode() RunInstructionInfo() send error : " + "sessionId=" + sessionId + ", jobId="
                    + jobId + ", facilityId=" + sessionNode.getId().getFacilityId() + " : "
                    + e.getClass().getSimpleName() + ", " + e.getMessage(), e);
        }
        return startCommand;
    }

    private void runJobSessionNode(String sessionId, String jobunitId, String jobId, String facilityId)
            throws JobInfoNotFound, InvalidRole, HinemosUnknown, JobMasterNotFound, FacilityNotFound {
        m_log.debug("runJobSessionNode() : sessionId=" + sessionId + ", jobunitid=" + jobunitId + ", jobId=" + jobId
                + ", facilityId=" + facilityId);
        JobSessionJobEntity sessionJob = QueryUtil.getJobSessionJobPK(sessionId, jobunitId, jobId);
        JobInfoEntity job = sessionJob.getJobInfoEntity();
        JobSessionNodeEntity sessionNode = QueryUtil.getJobSessionNodePK(sessionId, jobunitId, jobId, facilityId);

        //?
        RunInstructionInfo instructionInfo = new RunInstructionInfo();
        instructionInfo.setSessionId(sessionJob.getId().getSessionId());
        instructionInfo.setJobunitId(sessionJob.getId().getJobunitId());
        instructionInfo.setJobId(sessionJob.getId().getJobId());
        instructionInfo.setFacilityId(sessionNode.getId().getFacilityId());
        //?
        List<JobEnvVariableInfo> envInfoList = new ArrayList<JobEnvVariableInfo>();
        for (JobEnvVariableInfoEntity envEntity : job.getJobEnvVariableInfoEntities()) {
            JobEnvVariableInfo envInfo = new JobEnvVariableInfo();
            envInfo.setEnvVariableId(envEntity.getId().getEnvVariableId());
            envInfo.setValue(envEntity.getValue());
            envInfo.setDescription(envEntity.getDescription());
            envInfoList.add(envInfo);
        }
        instructionInfo.setJobEnvVariableInfoList(envInfoList);

        if (job.getJobType() == JobConstant.TYPE_MONITORJOB) {
            instructionInfo.setCommand(CommandConstant.MONITOR);
            instructionInfo.setCommandType(CommandTypeConstant.NORMAL);

            try {
                // HinemosManager?
                MonitorJobWorker.runJob(instructionInfo);

            } catch (Exception e) {
                m_log.warn("runJobSessionNode() : " + e.getClass().getSimpleName() + ", " + e.getMessage(), e);
            }
        } else if (job.getJobType() == JobConstant.TYPE_APPROVALJOB) {
            // ????Topic???????
            sessionNode.setStartDate(HinemosTime.currentTimeMillis());
            String jobFacilityId = job.getFacilityId();
            // ?????
            // ??
            String reqSentence = job.getApprovalReqSentence();
            reqSentence = ParameterUtil.replaceSessionParameterValue(sessionId, jobFacilityId, reqSentence);
            reqSentence = ParameterUtil.replaceReturnCodeParameter(sessionId, jobunitId, reqSentence);
            job.setApprovalReqSentence(reqSentence);

            // ????
            String mailTitle = job.getApprovalReqMailTitle();
            mailTitle = ParameterUtil.replaceSessionParameterValue(sessionId, jobFacilityId, mailTitle);
            mailTitle = ParameterUtil.replaceReturnCodeParameter(sessionId, jobunitId, mailTitle);
            job.setApprovalReqMailTitle(mailTitle);

            // ??
            String mailBody = job.getApprovalReqMailBody();
            mailBody = ParameterUtil.replaceSessionParameterValue(sessionId, jobFacilityId, mailBody);
            mailBody = ParameterUtil.replaceReturnCodeParameter(sessionId, jobunitId, mailBody);
            job.setApprovalReqMailBody(mailBody);

            setMessage(sessionNode, MessageConstant.WAIT_APPROVAL.getMessage());
            //?
            SendApprovalMail sendMail = new SendApprovalMail();
            sendMail.sendRequest(job, sessionNode.getApprovalRequestUser());
        } else {
            String startCommand = job.getStartCommand();

            // ?????
            startCommand = ParameterUtil.replaceSessionParameterValue(sessionId,
                    sessionNode.getId().getFacilityId(), job.getStartCommand());

            //?????(#[RETURN:jobid:facilityId])
            startCommand = ParameterUtil.replaceReturnCodeParameter(sessionId, jobunitId, startCommand);
            instructionInfo.setCommand(startCommand);
            instructionInfo.setSpecifyUser(job.getSpecifyUser());
            instructionInfo.setUser(job.getEffectiveUser());
            instructionInfo.setCommandType(CommandTypeConstant.NORMAL);

            //
            if (instructionInfo.getCommand().equals(CommandConstant.ADD_PUBLIC_KEY)
                    || instructionInfo.getCommand().equals(CommandConstant.DELETE_PUBLIC_KEY)) {
                //?

                //ID?ID???
                JobSessionJobEntity argumentSessionJob = QueryUtil.getJobSessionJobPK(sessionId, jobunitId,
                        job.getArgumentJobId());
                String result = argumentSessionJob.getResult();

                //?????ID
                instructionInfo.setPublicKey(result);
            } else if (instructionInfo.getCommand().equals(CommandConstant.GET_FILE_LIST)) {
                //?

                //?????
                instructionInfo.setFilePath(job.getArgument());
            } else if (instructionInfo.getCommand().equals(CommandConstant.GET_CHECKSUM)) {
                //??

                //???
                instructionInfo.setFilePath(job.getArgument());
            } else if (instructionInfo.getCommand().equals(CommandConstant.CHECK_CHECKSUM)) {
                //??

                //ID?ID???
                JobSessionJobEntity argumentSessionJob = QueryUtil.getJobSessionJobPK(sessionId, jobunitId,
                        job.getArgumentJobId());
                String result = argumentSessionJob.getResult();

                //?
                instructionInfo.setCheckSum(result);
                //???
                instructionInfo.setFilePath(job.getArgument());
            } else if (instructionInfo.getJobId().endsWith(CreateHulftJob.HULOPLCMD)) {
                //ID?ID???
                JobSessionJobEntity argumentSessionJob = QueryUtil.getJobSessionJobPK(sessionId, jobunitId,
                        job.getArgumentJobId());
                String result = argumentSessionJob.getResult();

                // TRID
                instructionInfo.setCommand(instructionInfo.getCommand() + " " + result);
            }

            try {
                //Topic??
                SendTopic.put(instructionInfo);

            } catch (Exception e) {
                m_log.warn("runJobSessionNode() : " + e.getClass().getSimpleName() + ", " + e.getMessage(), e);
            }
        }
    }

    /**
     * ????
     *
     * @param info ?
     * @return ?????true??????????false
     * @throws HinemosUnknown
     * @throws JobInfoNotFound
     * @throws FacilityNotFound
     * @throws EntityExistsException
     * @throws InvalidRole
     */
    public boolean endNode(RunResultInfo info)
            throws HinemosUnknown, JobInfoNotFound, EntityExistsException, FacilityNotFound, InvalidRole {
        m_log.info("endNode() : sessionId=" + info.getSessionId() + ", jobunitId=" + info.getJobunitId()
                + ", jobId=" + info.getJobId() + ", facilityId=" + info.getFacilityId() + ", commandType="
                + info.getCommandType());

        //?
        //NORMAL??????????STOP???
        //STOP????NORMAL???????
        //??????NORMAL???(??????????)
        JobSessionNodeEntity jobNode = QueryUtil.getJobSessionNodePK(info.getSessionId(), info.getJobunitId(),
                info.getJobId(), info.getFacilityId());
        int status = jobNode.getStatus();
        int commandType = info.getCommandType();
        if ((commandType == CommandTypeConstant.NORMAL && status != StatusConstant.TYPE_RUNNING)
                || (commandType == CommandTypeConstant.STOP && status != StatusConstant.TYPE_STOPPING)) {
            // ????????????????????
            // ??
            m_log.info("ignore command, commandType=" + commandType + ", status=" + status);
            return false;
        }

        if (commandType == CommandTypeConstant.NORMAL || commandType == CommandTypeConstant.STOP) {
            if (!endNodeNormalStop(info)) {
                // ????????????false?
                return false;
            }
        }

        endNodeFinish(info.getSessionId(), info.getJobunitId(), info.getJobId(), info.getFacilityId(),
                info.getCommand(), info.getFileList());
        return true;
    }

    //     * @return ?????true??????????false?
    private boolean endNodeNormalStop(RunResultInfo info) throws JobInfoNotFound, InvalidRole {
        //ID?ID???
        JobSessionJobEntity sessionJob = QueryUtil.getJobSessionJobPK(info.getSessionId(), info.getJobunitId(),
                info.getJobId());
        JobInfoEntity job = sessionJob.getJobInfoEntity();
        JobSessionNodeEntity sessionNode = QueryUtil.getJobSessionNodePK(info.getSessionId(), info.getJobunitId(),
                info.getJobId(), info.getFacilityId());

        boolean isSessionNodeRunning = false;
        if (sessionNode.getStatus() == StatusConstant.TYPE_RUNNING) {
            isSessionNodeRunning = true;
        }

        //??
        if (info.getStatus() == RunStatusConstant.START) {
            //??

            if (sessionNode.getStartDate() == null) {
                //?
                sessionNode.setStartDate(info.getTime());
                if (job.getJobType() != JobConstant.TYPE_MONITORJOB) {
                    setMessage(sessionNode, MessageConstant.WAIT_COMMAND_END.getMessage());
                } else {
                    setMessage(sessionNode, MessageConstant.WAIT_MONITOR_RESPONSE.getMessage());
                }

                AgentInfo agentInfo = AgentConnectUtil.getAgentInfo(info.getFacilityId());
                if (agentInfo != null) {
                    sessionNode.setStartupTime(agentInfo.getStartupTime());
                    String instanceId = agentInfo.getInstanceId();
                    if (instanceId == null) {
                        instanceId = "";
                    }
                    sessionNode.setInstanceId(instanceId);
                } else {
                    m_log.warn("agentInfo is null");
                }

                //???
                m_log.debug("agent check OK : status=" + info.getStatus() + ", sessionId=" + info.getSessionId()
                        + ", jobId=" + info.getJobId() + ", facilityId=" + info.getFacilityId());

            } else {
                m_log.info("endNodeSetStatus() : this messsage is already received. drop message." + " sessionId="
                        + info.getSessionId() + ", jobId=" + info.getJobId() + ", facilityId="
                        + info.getFacilityId());
                // ?????????????????false?
                return false;
            }
        } else {
            boolean retryFlag = true;

            //??????

            if (info.getStatus() == RunStatusConstant.END && (job.getNormalEndValueFrom() <= info.getEndValue()
                    && info.getEndValue() <= job.getNormalEndValueTo())) {
                retryFlag = false;
            } else {
                if (!job.getCommandRetryFlg().booleanValue()) {
                    retryFlag = false;
                }
            }

            if (info.getStatus() == RunStatusConstant.END) {
                //??
                if (retryFlag && retryJob(sessionNode, sessionJob, info, job.getCommandRetry())) {
                    //??
                    return false;
                }

                //????????
                if (sessionJob.getStartDate() != null || sessionNode.getStartDate() != null) {
                    if (sessionJob.getEndDate() == null || sessionJob.getStatus() == StatusConstant.TYPE_RUNNING
                            || sessionJob.getStatus() == StatusConstant.TYPE_SUSPEND
                            || sessionJob.getStatus() == StatusConstant.TYPE_STOPPING) {

                        //?
                        if (sessionNode.getStatus() == StatusConstant.TYPE_RUNNING) {
                            //????
                            sessionNode.setStatus(StatusConstant.TYPE_END);
                            //
                            sessionNode.setEndDate(info.getTime());
                        } else if (sessionNode.getStatus() == StatusConstant.TYPE_STOPPING) {
                            if (info.getCommandType() == CommandTypeConstant.STOP) {
                                //???????
                                sessionNode.setStatus(StatusConstant.TYPE_STOP);
                            }
                        }
                        //???
                        if (job.getJobType() == JobConstant.TYPE_APPROVALJOB) {
                            setMessage(sessionNode, info.getMessage());
                        } else if (info.getCommandType() == CommandTypeConstant.STOP
                                && info.getStopType() == CommandStopTypeConstant.DESTROY_PROCESS) {
                            // ??
                            //
                            setMessage(sessionNode, MessageConstant.JOB_PROCESS_SHUTDOWN.getMessage());
                        } else {
                            // ??
                            // ???
                            if (job.getJobCommandParamInfoEntities() != null
                                    && job.getJobCommandParamInfoEntities().size() > 0) {
                                List<JobCommandParamInfoEntity> jobCommandParamInfoEntityList = job
                                        .getJobCommandParamInfoEntities();
                                // ID?ID????
                                JobSessionJobEntity sessionJobEntity = QueryUtil.getJobSessionJobPK(
                                        info.getSessionId(), info.getJobunitId(),
                                        job.getJobSessionJobEntity().getJobSessionEntity().getJobId());
                                List<JobParamInfoEntity> jobParamInfoList = sessionJobEntity.getJobInfoEntity()
                                        .getJobParamInfoEntities();
                                for (JobCommandParamInfoEntity jobCommandParamInfoEntity : jobCommandParamInfoEntityList) {
                                    String value = "";
                                    String createParamId = jobCommandParamInfoEntity.getId().getParamId() + ":"
                                            + info.getFacilityId();
                                    // ???
                                    if (jobCommandParamInfoEntity.getJobStandardOutputFlg()) {
                                        if (info.getMessage() != null) {
                                            Matcher m = Pattern.compile(jobCommandParamInfoEntity.getValue())
                                                    .matcher(info.getMessage());
                                            if (m.find()) {
                                                try {
                                                    value = m.group(1);
                                                } catch (IndexOutOfBoundsException e) {
                                                    m_log.warn(String.format(
                                                            "not contain group paragraph in pattern for message."
                                                                    + " facilityId=%s, jobunitId=%s, jobId=%s, paramId=%s, message=%s",
                                                            info.getFacilityId(), info.getJobunitId(),
                                                            info.getJobId(),
                                                            jobCommandParamInfoEntity.getId().getParamId(),
                                                            info.getMessage()));
                                                }
                                            } else {
                                                // ????
                                                m_log.debug(String.format(
                                                        "variable not match. facilityId=%s, jobunitId=%s, jobId=%s, paramId=%s, message=%s",
                                                        info.getFacilityId(), info.getJobunitId(), info.getJobId(),
                                                        jobCommandParamInfoEntity.getId().getParamId(),
                                                        info.getMessage()));
                                            }
                                        } else {
                                            // ???
                                            m_log.warn(String.format(
                                                    "Not foudnd previous post. facilityId=%s, jobunitId=%s, jobId=%s, paramId=%s, message=%s",
                                                    info.getFacilityId(), info.getJobunitId(), info.getJobId(),
                                                    jobCommandParamInfoEntity.getId().getParamId(),
                                                    info.getMessage()));
                                        }
                                    } else {
                                        // ????
                                        value = jobCommandParamInfoEntity.getValue();
                                    }
                                    // ??
                                    boolean chkFlg = false;
                                    for (JobParamInfoEntity jobParamInfo : jobParamInfoList) {
                                        if (jobParamInfo.getId().getJobId().equals(
                                                job.getJobSessionJobEntity().getJobSessionEntity().getJobId())
                                                && jobParamInfo.getId().getJobunitId()
                                                        .equals(job.getId().getJobunitId())
                                                && jobParamInfo.getId().getSessionId()
                                                        .equals(job.getId().getSessionId())
                                                && jobParamInfo.getId().getParamId().equals(createParamId)) {
                                            jobParamInfo.setValue(value);
                                            chkFlg = true;
                                            break;
                                        }
                                    }
                                    // ????????
                                    if (!chkFlg) {
                                        JobParamInfoEntity jobParamInfoEntity = new JobParamInfoEntity(job,
                                                createParamId);
                                        // ID?ID?
                                        jobParamInfoEntity.getId().setJobId(
                                                job.getJobSessionJobEntity().getJobSessionEntity().getJobId());
                                        jobParamInfoEntity.setParamType(JobParamTypeConstant.TYPE_SYSTEM_JOB);
                                        jobParamInfoEntity.setValue(value);
                                        jobParamInfoList.add(jobParamInfoEntity);
                                        sessionJobEntity.getJobInfoEntity()
                                                .setJobParamInfoEntities(jobParamInfoList);
                                    }
                                }
                            }
                            //
                            setMessage(sessionNode,
                                    "stdout=" + info.getMessage() + ", stderr=" + info.getErrorMessage());
                        }

                        //
                        sessionNode.setEndValue(info.getEndValue());

                        //
                        if (info.getCommand().equals(CommandConstant.GET_PUBLIC_KEY)) {
                            //??
                            sessionNode.setResult(info.getPublicKey());
                        } else if (info.getCommand().equals(CommandConstant.GET_CHECKSUM)) {
                            //??
                            sessionNode.setResult(info.getCheckSum());
                        } else if (info.getJobId().endsWith(CreateHulftJob.UTLSEND)
                                && CreateHulftJob.isHulftMode()) {
                            //TRID?
                            sessionNode.setResult(info.getMessage());
                        }
                    } else {
                        m_log.debug("endNodeSetStatus() : this messsage is already received. drop message."
                                + " sessionId=" + info.getSessionId() + ", jobId=" + info.getJobId()
                                + ", facilityId=" + info.getFacilityId());
                    }
                } else {
                    // ????????
                    m_log.info("endNodeSetStatus() : this messsage does not have start time. drop message."
                            + " sessionId=" + info.getSessionId() + ", jobId=" + info.getJobId() + ", facilityId="
                            + info.getFacilityId());
                }
            } else if (info.getStatus() == RunStatusConstant.ERROR) {
                //??
                if (retryFlag && retryJob(sessionNode, sessionJob, info, job.getCommandRetry())) {
                    //??
                    return false;
                }

                //??
                if (sessionNode.getStatus() == StatusConstant.TYPE_RUNNING) {
                    //???
                    if (job.getMessageRetryEndFlg().booleanValue()) {
                        //??????
                        sessionNode.setStatus(StatusConstant.TYPE_END);

                        //
                        sessionNode.setEndDate(HinemosTime.currentTimeMillis());
                        //
                        sessionNode.setEndValue(job.getMessageRetryEndValue());
                    } else {
                        //??????
                        sessionNode.setStatus(StatusConstant.TYPE_ERROR);
                    }
                } else if (sessionNode.getStatus() == StatusConstant.TYPE_STOPPING) {
                    //?????????
                    sessionNode.setStatus(StatusConstant.TYPE_STOP);
                    sessionNode.setEndValue(info.getEndValue());
                }

                //
                setMessage(sessionNode, info.getMessage() + info.getErrorMessage());
            }

            if (sessionNode.getStartDate() == null) {
                // ????????
                m_log.debug("set status buffer : status=" + info.getStatus() + ", sessionId=" + info.getSessionId()
                        + ", jobId=" + info.getJobId() + ", facilityId=" + info.getFacilityId());
            }

            //?????????
            if (isSessionNodeRunning && sessionNode.getStatus() != StatusConstant.TYPE_RUNNING) {
                JpaTransactionManager jtm = new JpaTransactionManager();
                jtm.addCallback(new FromRunningAfterCommitCallback(sessionNode.getId()));
            }

        }
        return true;
    }

    protected void endNodeFinish(String sessionId, String jobunitId, String jobId, String facilityId,
            String command, List<String> fileList)
            throws JobInfoNotFound, HinemosUnknown, EntityExistsException, FacilityNotFound, InvalidRole {
        //ID?ID???
        JobSessionJobEntity sessionJob = QueryUtil.getJobSessionJobPK(sessionId, jobunitId, jobId);
        JobInfoEntity job = sessionJob.getJobInfoEntity();
        JobSessionNodeEntity sessionNode = QueryUtil.getJobSessionNodePK(sessionId, jobunitId, jobId, facilityId);
        m_log.debug("endNodeFinish() : status=" + sessionNode.getStatus() + ", facilityId="
                + sessionNode.getId().getFacilityId());
        //?
        if (sessionNode.getStatus() == StatusConstant.TYPE_STOP) {
            //????
            if (sessionJob.getStatus() == StatusConstant.TYPE_STOPPING && checkAllNodeStop(sessionJob)) {
                //???
                //??
                sessionJob.setStatus(StatusConstant.TYPE_STOP);
                //??
                new OperateStopOfJob().stopJob2(sessionId, jobunitId, jobId);
                //??
                int flg = sessionJob.getDelayNotifyFlg();
                //?????
                int operationFlg = DelayNotifyConstant.getOperation(flg);
                if (operationFlg == DelayNotifyConstant.STOP_SET_END_VALUE) {
                    //????[]????[]?
                    new OperateMaintenanceOfJob().maintenanceJob(sessionId, jobunitId, jobId,
                            StatusConstant.TYPE_END_END_DELAY, job.getEndDelayOperationEndStatus(),
                            job.getEndDelayOperationEndValue());
                }
            }
        } else {
            if (sessionJob.getJobInfoEntity().getProcessMode() == ProcessingMethodConstant.TYPE_RETRY) {
                //????
                if (sessionJob.getStatus() == StatusConstant.TYPE_SUSPEND) {
                    return;
                }
                if (checkAllNodeEnd(sessionJob)) {
                    m_log.info("endNodeFinish() : all nodes end (type retry) " + facilityId);
                    Collection<JobSessionNodeEntity> nodeList = sessionJob.getJobSessionNodeEntities();
                    for (JobSessionNodeEntity node : nodeList) {
                        // ???????
                        if (node.getStatus() == StatusConstant.TYPE_WAIT) {
                            JobMultiplicityCache.removeWait(node.getId());
                            node.setStatus(StatusConstant.TYPE_END);
                            setMessage(node, "didn't execute");
                        }
                    }
                    //????
                    new JobSessionJobImpl().endJob(sessionId, jobunitId, jobId, sessionNode.getResult(), true);
                } else {
                    m_log.info("endNodeFinish() : next node " + sessionJob.getId());
                    // ???
                    startNode(sessionJob.getId().getSessionId(), sessionJob.getId().getJobunitId(),
                            sessionJob.getId().getJobId());
                }
            } else {
                //????
                if (sessionJob.getStatus() != StatusConstant.TYPE_SUSPEND && checkAllNodeEnd(sessionJob)) {
                    //??
                    //?
                    if (CommandConstant.GET_FILE_LIST.equals(command)) {
                        new CreateFileJob().createFileJobNet(sessionJob, fileList);
                    }
                    //????
                    new JobSessionJobImpl().endJob(sessionId, jobunitId, jobId, sessionNode.getResult(), true);
                }
            }
        }
    }

    /**
     * ??????
     *
     * @param sessionJob 
     * @return true??false??
     */
    protected boolean checkAllNodeStop(JobSessionJobEntity sessionJob) {
        m_log.debug("checkAllNodeStop() : sessionId=" + sessionJob.getId().getSessionId() + ", jobId="
                + sessionJob.getId().getJobId());

        boolean stop = true;
        for (JobSessionNodeEntity sessionNode : sessionJob.getJobSessionNodeEntities()) {
            //?????
            if (sessionNode.getStatus() == StatusConstant.TYPE_STOPPING
                    || sessionNode.getStatus() == StatusConstant.TYPE_RUNNING) {
                stop = false;
                break;
            }
        }

        return stop;
    }

    /**
     * ?????
     *
     * @param sessionJob 
     * @return true?false
     */
    private boolean checkAllNodeEnd(JobSessionJobEntity sessionJob) {
        m_log.debug("checkAllNodeEnd() : sessionId=" + sessionJob.getId().getSessionId() + ", jobId="
                + sessionJob.getId().getJobId());

        //false??
        boolean end = false;

        if (sessionJob.getJobInfoEntity().getProcessMode() == ProcessingMethodConstant.TYPE_RETRY) {
            //???????????????
            Integer endStatus = null;
            try {
                endStatus = new JobSessionJobImpl().checkEndStatus(sessionJob.getId().getSessionId(),
                        sessionJob.getId().getJobunitId(), sessionJob.getId().getJobId());
            } catch (JobInfoNotFound e) {
                // ?????
                m_log.info("checkAllNodeEnd " + e.getMessage(), e);
            } catch (InvalidRole e) {
                m_log.info("checkAllNodeEnd " + e.getMessage(), e);
            } catch (Exception e) {
                m_log.info("checkAllNodeEnd " + e.getMessage(), e);
            }
            if (endStatus != null && endStatus == EndStatusConstant.TYPE_NORMAL) {
                return true;
            }
        }
        end = true;
        for (JobSessionNodeEntity sessionNode : sessionJob.getJobSessionNodeEntities()) {
            //????????OK
            if (!StatusConstant.isEndGroup(sessionNode.getStatus())) {
                end = false;
                break;
            }
        }
        return end;
    }

    /**
     * ????
     */
    public HashMap<String, List<JobSessionNodeEntityPK>> checkTimeoutAll() throws JobInfoNotFound {
        HinemosEntityManager em = new JpaTransactionManager().getEntityManager();
        Collection<JobSessionNodeEntity> collection = null;
        collection = em.createNamedQuery("JobSessionNodeEntity.findByStatusStartIsNull", JobSessionNodeEntity.class)
                .setParameter("status", StatusConstant.TYPE_RUNNING).getResultList();

        HashMap<String, List<JobSessionNodeEntityPK>> map = new HashMap<String, List<JobSessionNodeEntityPK>>();

        for (JobSessionNodeEntity node : collection) {
            if (node.getStartDate() == null) {
                ArrayList<JobSessionNodeEntityPK> list = (ArrayList<JobSessionNodeEntityPK>) map
                        .get(node.getId().getSessionId());
                if (list == null) {
                    list = new ArrayList<JobSessionNodeEntityPK>();
                }
                list.add(node.getId());
                map.put(node.getId().getSessionId(), list);
            }
        }

        return map;
    }

    /**
     * ????
     *
     * @param sessionId ID
     * @param jobId ID
     * @throws JobInfoNotFound
     */
    public void checkTimeout(JobSessionNodeEntityPK pk) throws JobInfoNotFound {
        String sessionId = pk.getSessionId();
        String jobunitId = pk.getJobunitId();
        String jobId = pk.getJobId();
        String facilityId = pk.getFacilityId();
        JobSessionNodeEntity sessionNode = QueryUtil.getJobSessionNodePK(sessionId, jobunitId, jobId, facilityId);
        m_log.debug("checkTimeout() : sessionId=" + sessionId + ", jobunitId=" + jobunitId + ", jobId=" + jobId
                + ", facilityId=" + facilityId);

        //??
        if (sessionNode.getStatus() != StatusConstant.TYPE_RUNNING) {
            // 1?1????????
            // ??
            m_log.info("checkTimeout() : status is not running");
            return;
        }

        if (sessionNode.getStartDate() != null) {
            // ?????
            // 1?1?checkTimeout????????
            m_log.info("checkTimeout() : startDate is not null");
            return;
        }
        int retry = sessionNode.getRetryCount();
        int messageRetry = sessionNode.getJobSessionJobEntity().getJobInfoEntity().getMessageRetry();
        if (retry >= messageRetry) {
            //????????AgentTimeoutError??

            m_log.info("checkTimeout() : Agent Check NG : sessionId=" + sessionId + ", jobId=" + jobId
                    + ", facilityId=" + facilityId);

            //??
            RunResultInfo info = new RunResultInfo();
            info.setSessionId(sessionId);
            info.setJobunitId(jobunitId);
            info.setJobId(jobId);
            info.setFacilityId(facilityId);
            info.setCommand("");
            info.setCommandType(CommandTypeConstant.NORMAL);
            info.setStatus(RunStatusConstant.ERROR);
            info.setMessage(MessageConstant.AGENT_TIMEOUT_ERROR.getMessage() + " (" + retry + ")");
            info.setErrorMessage("");
            try {
                endNode(info);
            } catch (InvalidRole | JobInfoNotFound e) {
                m_log.warn("setting status failure. (sessionId = " + info.getSessionId() + ", facilityId = "
                        + info.getFacilityId() + ", status = " + info.getStatus() + ", commandType = "
                        + info.getCommandType() + ")" + " (" + e.getClass().getName() + ")");
            } catch (Exception e) {
                m_log.warn("checkTimeout() RunresultInfo send error : sessionId=" + sessionId + ", jobId=" + jobId
                        + ", facilityId=" + facilityId + ",  : " + e.getClass().getSimpleName() + ", "
                        + e.getMessage() + " (" + e.getClass().getName() + ")", e);
            }
        } else {
            int retryCount = sessionNode.getRetryCount();
            retryCount++;
            sessionNode.setRetryCount(retryCount);
            try {
                //Topic??
                m_log.debug("checkTimeout() : send RunInstructionInfo() : sessionId=" + sessionId + ", jobId="
                        + jobId + ", facilityId=" + facilityId + ", retry=" + retryCount);

                runJobSessionNode(sessionId, jobunitId, jobId, facilityId);
            } catch (InvalidRole | HinemosUnknown | JobMasterNotFound | FacilityNotFound e) {
                m_log.warn("checkTimeout() RunInstructionInfo() send error : sessionId=" + sessionId + ", jobId="
                        + jobId + ", facilityId=" + facilityId + " : " + e.getClass().getSimpleName() + ", "
                        + e.getMessage());
            } catch (Exception e) {
                m_log.warn("checkTimeout() RunInstructionInfo() send error : sessionId=" + sessionId + ", jobId="
                        + jobId + ", facilityId=" + facilityId + " : " + e.getClass().getSimpleName() + ", "
                        + e.getMessage(), e);
            }
        }
    }

    /**
     * ???????
     *
     * @param jobSessionNodeEntity 
     * @param monitorTypeId ID
     * @return
     * @throws HinemosUnknown
     * @throws JobInfoNotFound
     * @throws InvalidRole 
     */
    public void checkMonitorJobTimeout(JobSessionNodeEntity jobSessionNodeEntity, String monitorTypeId)
            throws HinemosUnknown, JobInfoNotFound, InvalidRole {
        String sessionId = jobSessionNodeEntity.getId().getSessionId();
        String jobunitId = jobSessionNodeEntity.getId().getJobunitId();
        String jobId = jobSessionNodeEntity.getId().getJobId();
        String facilityId = jobSessionNodeEntity.getId().getFacilityId();
        m_log.debug("checkMonitorJobTimeout() : sessionId=" + sessionId + ", jobunitId=" + jobunitId + ", jobId="
                + jobId + ", facilityId=" + facilityId + ", monitorTypeId=" + monitorTypeId);

        // ??
        if (monitorTypeId == null || (!monitorTypeId.equals(HinemosModuleConstant.MONITOR_SYSTEMLOG)
                && !monitorTypeId.equals(HinemosModuleConstant.MONITOR_SNMPTRAP)
                && !monitorTypeId.equals(HinemosModuleConstant.MONITOR_LOGFILE)
                && !monitorTypeId.equals(HinemosModuleConstant.MONITOR_WINEVENT)
                && !monitorTypeId.equals(HinemosModuleConstant.MONITOR_CUSTOMTRAP_N)
                && !monitorTypeId.equals(HinemosModuleConstant.MONITOR_CUSTOMTRAP_S))) {
            return;
        }

        // 
        JobInfoEntity jobInfoEntity = jobSessionNodeEntity.getJobSessionJobEntity().getJobInfoEntity();

        if (jobInfoEntity.getMonitorWaitTime() == null || jobInfoEntity.getMonitorWaitTime() == 0) {
            // ??????????
            return;
        }

        // ?
        // ??
        long startDate = jobSessionNodeEntity.getStartDate();
        Calendar work = HinemosTime.getCalendarInstance();
        work.setTimeInMillis(startDate);
        work.getTime();
        work.add(Calendar.MINUTE, jobInfoEntity.getMonitorWaitTime());
        Long check = work.getTimeInMillis();
        if (check <= HinemosTime.currentTimeMillis()) {
            // ?
            RunInstructionInfo runInstructionInfo = RunHistoryUtil.findRunHistory(sessionId, jobunitId, jobId,
                    jobSessionNodeEntity.getId().getFacilityId());
            if (runInstructionInfo == null) {
                //?
                runInstructionInfo = new RunInstructionInfo();
                runInstructionInfo.setSessionId(sessionId);
                runInstructionInfo.setJobunitId(jobunitId);
                runInstructionInfo.setJobId(jobId);
                runInstructionInfo.setFacilityId(jobSessionNodeEntity.getId().getFacilityId());
                runInstructionInfo.setSpecifyUser(jobInfoEntity.getSpecifyUser());
                runInstructionInfo.setUser(jobInfoEntity.getEffectiveUser());
                runInstructionInfo.setCommandType(CommandTypeConstant.NORMAL);
                runInstructionInfo.setCommand(CommandConstant.MONITOR);
                runInstructionInfo.setStopType(jobInfoEntity.getStopType());
            }
            MonitorJobWorker.endMonitorJob(runInstructionInfo, monitorTypeId,
                    MessageConstant.MESSAGE_JOB_MONITOR_RESULT_NOT_FOUND.getMessage(), "", RunStatusConstant.END,
                    jobInfoEntity.getMonitorWaitEndValue());
        }
    }

    private static class JobPriorityComparator implements Comparator<JobSessionNodeEntity>, Serializable {
        /**
         * 
         */
        private static final long serialVersionUID = 1L;

        // ??JobSessionNodeEntity????????
        @Override
        public int compare(JobSessionNodeEntity s, JobSessionNodeEntity t) {
            int ret = 0;
            try {
                String facilityId_s = s.getId().getFacilityId();
                String facilityId_t = t.getId().getFacilityId();

                /*
                 *  ?
                 * ??????(t??????return ????)
                 */
                int priority_s = NodeProperty.getProperty(facilityId_s).getJobPriority();
                int priority_t = NodeProperty.getProperty(facilityId_t).getJobPriority();
                ret = priority_t - priority_s;
                if (ret != 0) {
                    return ret;
                }

                /*
                 * ?(run / wait)
                 * ???????
                 * ???????????????
                 * return (rs / ms - rt / mt)
                 *  return (rs * mt - rt * ms)
                 *  =???mt?ms?
                 */
                int run_s = JobMultiplicityCache.getRunningMultiplicity(facilityId_s);
                int multi_s = NodeProperty.getProperty(facilityId_s).getJobMultiplicity();
                int run_t = JobMultiplicityCache.getRunningMultiplicity(facilityId_t);
                int multi_t = NodeProperty.getProperty(facilityId_t).getJobMultiplicity();
                ret = run_s * multi_t - run_t * multi_s;
                if (ret != 0) {
                    return ret;
                }
                ret = multi_t - multi_s;
                if (ret != 0) {
                    return ret;
                }

                // facilityId
                ret = facilityId_s.compareTo(facilityId_t);
                if (ret != 0) {
                    return ret;
                }
            } catch (FacilityNotFound e) {
                m_log.warn("NodeComparator " + e.getMessage());
            }
            return 0;
        }
    }

    /**
     * ?????
     * @param sessionNode
     * @param newMsg
     */
    public void setMessage(JobSessionNodeEntity sessionNode, String newMsg) {
        String msg;
        Date date = HinemosTime.getDateInstance();
        SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        df.setTimeZone(HinemosTime.getTimeZone());
        String dateStr = df.format(date);
        String header = "[" + dateStr + "] ";
        String oldMsg = sessionNode.getMessage();

        //??????????
        Pattern pattern = Pattern.compile("\r\n$");
        Matcher m = pattern.matcher(newMsg);
        if (m.find() == false) {
            pattern = Pattern.compile("\n$");
            m = pattern.matcher(newMsg);
        }
        newMsg = m.replaceAll("");

        if (oldMsg == null || oldMsg.equals("")) {
            msg = header + newMsg;
        } else {
            //??????
            msg = header + newMsg + "\r\n" + oldMsg;
        }

        //???
        int msgMaxLen = HinemosPropertyUtil.getHinemosPropertyNum("job.message.max.length", Long.valueOf(2048))
                .intValue();
        if (msg.length() > msgMaxLen) {
            msg = msg.substring(0, msgMaxLen);
        }
        sessionNode.setMessage(msg);
    }

    private boolean retryJob(JobSessionNodeEntity sessionNode, JobSessionJobEntity sessionJob, RunResultInfo info,
            int maxRetry) {

        if (sessionNode.getStatus() != StatusConstant.TYPE_RUNNING) {
            return false;
        }

        if (sessionJob.getStatus() == StatusConstant.TYPE_SUSPEND) {
            setMessage(sessionNode, MessageConstant.SUSPEND.getMessage());
            sessionNode.setStatus(StatusConstant.TYPE_WAIT);
            sessionNode.setStartDate(null);
            return false;
        } else if (sessionJob.getStatus() != StatusConstant.TYPE_RUNNING) {
            return false;
        }

        //
        int errorCount = sessionNode.getErrorRetryCount();
        m_log.debug("maxRetry:" + maxRetry + " errorCount:" + errorCount + " " + (maxRetry > errorCount) + ", "
                + sessionNode.getId());
        if (maxRetry > errorCount) {
            //????
            int jobRetryInterval = HinemosPropertyUtil
                    .getHinemosPropertyNum("job.retry.interval", Long.valueOf(10 * 1000)).intValue();
            try {
                Thread.sleep(jobRetryInterval);
            } catch (InterruptedException e) {
                m_log.warn("retryJob() : " + e.getClass().getSimpleName() + ", " + e.getMessage(), e);
                return false;
            }

            //??????????
            //
            errorCount++;
            m_log.debug("errRtryCnt++=" + errorCount);

            //DB
            String msg = info.getMessage() + info.getErrorMessage();
            setMessage(sessionNode, msg);
            setMessage(sessionNode, MessageConstant.RETRYING.getMessage() + "(" + errorCount + ")");
            sessionNode.setErrorRetryCount(errorCount);
            sessionNode.setStatus(StatusConstant.TYPE_WAIT);
            sessionNode.setStartDate(null);

            //?
            if (checkMultiplicity(sessionNode)) {
                JpaTransactionManager jtm = new JpaTransactionManager();
                jtm.addCallback(new FromRunningAfterCommitCallback(sessionNode.getId()));
                jtm.addCallback(new ToRunningAfterCommitCallback(sessionNode.getId()));
                return true;
            }
        }

        return false;
    }

    /**
     * Hinemos????????
     * @param facilityId ID
     * @param agentInfo 
     * @param isNormalEnd ????????
     */
    public void endNodeByAgent(String facilityId, AgentInfo agentInfo, boolean isNormalEnd) {
        String queryName = isNormalEnd ? "JobSessionNodeEntity.findByFacilityIdStatus"
                : "JobSessionNodeEntity.findByDifferentStartuptime";

        JpaTransactionManager jtm = new JpaTransactionManager();
        jtm.begin();

        String instanceId = agentInfo.getInstanceId();
        if (instanceId == null) {
            instanceId = "";
        }

        //??
        HinemosEntityManager em = new JpaTransactionManager().getEntityManager();
        List<JobSessionNodeEntity> list = null;
        list = em.createNamedQuery(queryName, JobSessionNodeEntity.class)
                .setParameter("status", StatusConstant.TYPE_RUNNING).setParameter("facilityId", facilityId)
                .setParameter("startupTime", agentInfo.getStartupTime()).setParameter("instanceId", instanceId)
                .getResultList();

        for (JobSessionNodeEntity entity : list) {
            //??
            RunResultInfo info = new RunResultInfo();
            info.setSessionId(entity.getId().getSessionId());
            info.setJobunitId(entity.getId().getJobunitId());
            info.setJobId(entity.getId().getJobId());
            info.setFacilityId(facilityId);
            info.setCommand("");
            info.setCommandType(CommandTypeConstant.NORMAL);
            info.setStatus(RunStatusConstant.ERROR);
            info.setMessage(MessageConstant.MESSAGE_AGENT_STOPPED.getMessage());
            info.setErrorMessage("");
            m_log.info("endNodeByAgent " + entity.getId().toString());
            try {
                endNode(info);
            } catch (InvalidRole e) {
                m_log.info("setting status failure. (sessionId = " + info.getSessionId() + ", facilityId = "
                        + info.getFacilityId() + ", status = " + info.getStatus() + ", commandType = "
                        + info.getCommandType() + ")", e);
                jtm.rollback();
                return;
            } catch (JobInfoNotFound e) {
                m_log.info("setting status failure. (sessionId = " + info.getSessionId() + ", facilityId = "
                        + info.getFacilityId() + ", status = " + info.getStatus() + ", commandType = "
                        + info.getCommandType() + ")", e);
                jtm.rollback();
                return;
            } catch (Exception e) {
                m_log.warn("endNodeByAgent() RunresultInfo send error : sessionId=" + info.getSessionId()
                        + ", jobId=" + info.getJobId() + ", facilityId=" + facilityId + ",  : "
                        + e.getClass().getSimpleName() + ", " + e.getMessage(), e);
                jtm.rollback();
                return;
            }
        }
        jtm.commit();
    }

    /**
     * ?????
     *
     * @param info
     * @throws JobInfoNotFound
     * @throws HinemosUnknown
     * @throws InvalidRole
     * @throws FacilityNotFound 
     */
    public void approveJob(JobApprovalInfo info)
            throws JobInfoNotFound, HinemosUnknown, InvalidRole, FacilityNotFound, InvalidApprovalStatus {

        //ID?ID???
        JobSessionJobEntity sessionJob = QueryUtil.getJobSessionJobPK(info.getSessionId(), info.getJobunitId(),
                info.getJobId());
        // ??/
        JobInfoEntity jobInfo = sessionJob.getJobInfoEntity();

        //???
        List<JobSessionNodeEntity> nodeList = sessionJob.getJobSessionNodeEntities();
        JobSessionNodeEntity sessionNode = null;

        // ?????1??
        if (nodeList != null && nodeList.size() == 1) {
            //?
            sessionNode = nodeList.get(0);
        } else {
            m_log.error("approveJob() not found job info:" + info.getJobId());
            throw new JobInfoNotFound();
        }

        if (sessionNode.getApprovalStatus() == JobApprovalStatusConstant.TYPE_FINISHED
                || sessionNode.getApprovalStatus() == JobApprovalStatusConstant.TYPE_STOP) {
            m_log.warn("approveJob() There is no approved ready. :" + info.getJobId());
            throw new InvalidApprovalStatus(Messages.getString("MESSAGE_APPROVAL_INVALID_STATE"));
        }

        sessionNode.setApprovalStatus(JobApprovalStatusConstant.TYPE_FINISHED);
        sessionNode.setApprovalResult(info.getResult());
        sessionNode.setApprovalUser(info.getApprovalUser());
        sessionNode.setApprovalComment(info.getComment());

        // ?
        String approvaluser = info.getApprovalUser() == null ? "" : info.getApprovalUser();
        String comment = info.getComment() == null ? "" : info.getComment();
        String msg = approvaluser.equals("") ? comment : approvaluser + "" + comment;

        RunResultInfo resultInfo = new RunResultInfo();
        resultInfo.setSessionId(info.getSessionId());
        resultInfo.setJobunitId(info.getJobunitId());
        resultInfo.setJobId(info.getJobId());
        resultInfo.setFacilityId(sessionNode.getId().getFacilityId());
        resultInfo.setCommandType(CommandTypeConstant.NORMAL);
        resultInfo.setCommand("");
        resultInfo.setStopType(CommandStopTypeConstant.DESTROY_PROCESS);
        resultInfo.setStatus(RunStatusConstant.END);
        resultInfo.setTime(HinemosTime.currentTimeMillis());
        resultInfo.setEndValue(info.getResult());
        resultInfo.setMessage(msg);
        resultInfo.setErrorMessage("");

        endNode(resultInfo);

        //?
        SendApprovalMail sendMail = new SendApprovalMail();
        sendMail.sendResult(jobInfo, info);
    }

}