package com.eactive.eai.adapter.socket.service;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;

import com.eactive.eai.adapter.AdapterManager;
import com.eactive.eai.adapter.AdapterVO;
import com.eactive.eai.adapter.socket.common.CommonLib;
import com.eactive.eai.adapter.socket.common.DiagLogger;
import com.eactive.eai.adapter.socket.config.ConfigurationContext;
import com.eactive.eai.adapter.socket.config.SocketAdapterManager;
import com.eactive.eai.batch.common.BatchDirUtil;
import com.eactive.eai.batch.common.CalendarUtil;
import com.eactive.eai.batch.common.CommonKeys;
import com.eactive.eai.batch.common.LogUtil;
import com.eactive.eai.batch.common.StringUtil;
import com.eactive.eai.batch.doc.BatchDoc;
import com.eactive.eai.batch.flowController.BatchTargetVO;
import com.eactive.eai.batch.flowController.FlowControllerManager;
import com.eactive.eai.batch.message.EAIBatchMsgManager;
import com.eactive.eai.batch.osd.OutsideManager;
import com.eactive.eai.batch.osd.OutsideVO;
import com.eactive.eai.batch.rule.dirInfo.BatchJobInfoVO;
import com.eactive.eai.batch.rule.dirInfo.DirInfoManager;
import com.eactive.eai.batch.rule.ruleinfo.RuleInfoManager;
import com.eactive.eai.batch.rule.ruleinfo.RuleInfoVO;
import com.eactive.eai.batch.running.BatchRunningJobManager;
import com.eactive.eai.batch.scheduler.SchedulerMessageManager;
import com.eactive.eai.batch.scheduler.SchedulerMessageVO;
import com.eactive.eai.common.exception.ExceptionUtil;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.inbound.ResponseHandler;

public class IOboundServer extends Thread implements SocketService {

    private	ConfigurationContext    context;
    private SocketChannel           socketChannel;
    private SocketServer            proxy;

    private boolean					active;

    private long				 	firstActivity;
    private long				 	lastActivity;

    private int                     currentState;

    // pending message for checking operation
    private ByteBuffer              pendingMessage;
    private ByteBuffer              incomingMessage;
    private ByteBuffer              pollingMessage;

    // Logger
    private Logger                  logger;

    //
    private String                  remoteIPAddress;
	private String                  remotePort;

    AdapterVO 						adapter;
//    String 							transaction_code;

    private BatchDoc batchMsgDoc;
    //----------------------------------------------------------------


    public IOboundServer(ConfigurationContext context, SocketChannel socketChannel, SocketServer proxy) {
        String name = this.getName();
        this.setName( context.getAdapterName() + "-CONNECTION" + name.substring( name.lastIndexOf("-")) );

        this.context 		= context;
        this.socketChannel 	= socketChannel;
        this.proxy 			= proxy;

        firstActivity		= System.currentTimeMillis();
        lastActivity		= System.currentTimeMillis();

        pendingMessage      = ByteBuffer.allocate( 4096 );
        pendingMessage.clear();

        this.currentState   = isAckProtocol() ? CommonLib.NEGOTIATING_PROTOCOL : CommonLib.PROCESSING_PROTOCOL;

        logger              = SocketLogManager.getInstance().getLogger( context.getAdapterGroupName() );

        active              = true;
        remoteIPAddress     = this.socketChannel.socket().getInetAddress().getHostAddress();
		remotePort          = this.socketChannel.socket().getPort() +"";


    }

	public long getFirstActivity() {
		return this.firstActivity;
	}

	public long getLastActivity() {
		return this.lastActivity;
	}

    public String getRemotePort() {
        return this.remotePort;
    }

    public String getRemoteIPAddress() {
        return this.remoteIPAddress;
    }

    public boolean idle(long timeout) {
        long idleTime   = System.currentTimeMillis() - this.lastActivity;
        return ( idleTime > timeout );
    }

    public boolean isActive() {
        return active;
    }

    public synchronized void shutdown() {
        active          = false;
        
        notify();

        try {
        	if ( this.socketChannel == null ){
                logger.info("IOboundServer : socketChannel 이 null 입니다.");
                return;
        	}
            Socket socket = this.socketChannel.socket();
            if (socket == null) {
                logger.info("IOboundServer : socket 이 null 입니다.");
                return;
            }
            if (socket.isClosed()) {
                logger.info("IOboundServer : socket 이 이미 close 되었습니다.");
                return;
            }
            
            socket.setSoLinger(true, 100);
            if (socketChannel.isConnectionPending()) {
                logger.info("IOboundServer : socket channle isConnectionPending OK!!!");
                socketChannel.finishConnect();
            }
            socket.shutdownInput();
            socket.shutdownOutput();
            socket.close();
            socketChannel.close();

            logger.info("IOboundServer : IObound Socket Closed !!");

        } catch (Exception e) {
			logger.error( e.getMessage(), e);
        }
    }

    public Socket getCurrentSocket() {
    	return socketChannel.socket();
    }

    public boolean connect() {
    	return true;
    }

    public void disconnect() {
    	shutdown();
        proxy.quiesceShutdown(this);
        interrupt();
    }

    public void setControl(Object control) {
    }

    public void notifyMessage() {
    }

    public int getCurrentState() {
        return this.currentState;
    }

    // Writing전에 확인...
    public boolean isConnected() throws IOException {
    	boolean	flag = true;

    	if ( socketChannel.isConnected() && socketChannel.socket().isBound() ) {
    		ByteBuffer tmpBuffer = ByteBuffer.allocate( 1 );
            tmpBuffer.clear();
    		int i = socketChannel.read( tmpBuffer );
            if ( i > 0 ) {
                try {
                    pendingMessage.put( tmpBuffer.array() );
                } catch ( BufferOverflowException e ) {
                    throw new IOException("Socket 어플리케이션 프로토콜에러 발생 : " + e.getMessage());
                }
            }
    		if ( i == -1 ) {
    			flag = false;
    		}
    	} else {
    		flag = false;
    	}

    	return flag;
    }

    public void setLastActivity() {
        lastActivity = System.currentTimeMillis();
    }

    public void checkActivity() {
    }

    private boolean isAckProtocol() {
    	return this.context.isAckProtocol();
    }

    private long getTimeout() {
    	return	( this.context.getTimeout() * 1000L );
    }

    private int getTraceLevel() {
    	return context.getTraceLevel();
    }

    public ConfigurationContext getContext() {
        return context;
    }

    /**
     * IOboundServer 는 SocketServer 에서 생성되는 Thread 이다.
     *  외부에서 연결요청한 사항을 처리하기 위해 사용되며, 실제 배치처리에서는 실질적인 업무 플로우는
     *  JPD에서 처리하므로 여기에서는 소켓자체를 배치용 매니저에 등록해주고, 사용하기 쉽게 해주고,
     *  모든 context를 JPD 로 넘겨준다.
     */
    public void run() {
//        try {
//        	Thread.sleep(10000);
//        } catch( Throwable e ) {}

        SocketAdapterManager.getInstance().addConnection( this );
        //*** 어댑터에 대해 하나의 대외기관 연결정보(BJ05)만이 매핑되어 있어야 하는 것이 보장되어야 한다.
		logger.info("[IOboundServer] Group ["+context.getAdapterGroupName()+"] Adapter["+context.getAdapterName()+"]");
		adapter = AdapterManager.getInstance().getAdapterVO(context.getAdapterGroupName(), context.getAdapterName());

        int readLength = 0;
        try {
          readLength		= adapter.getContext().getLlFieldIndex() + adapter.getContext().getLlFieldLength();
        } catch (Exception e) {}
        if ( readLength < 1 ){
          	readLength = 9;
        }

        firstActivity	= System.currentTimeMillis();
        lastActivity	= firstActivity;

        String  socketInfo = "";
        
		incomingMessage = ByteBuffer.allocate( readLength );

        if ( getTraceLevel() >= DiagLogger.INFO ) {
            logger.info( CommonLib.getMessage("BICEAIASI002", new String[]{ context.getAdapterName(), socketInfo , Thread.currentThread().getName() }) );
        }
        // active 상태에서 LOOP
        while ( active ) {
        	
    		try {
    		    // length & message buffer clear
    			if ( incomingMessage != null ) {
                    incomingMessage.clear();

    			//logger.debug("incomingMessage-->" + incomingMessage.array().length);
    			//logger.debug("adapter.getContext().getLlFieldIndex()-->" + adapter.getContext().getLlFieldIndex());
    			//logger.debug("adapter.getContext().getLlFieldLength()-->" + adapter.getContext().getLlFieldLength());

                    processReadMessage( incomingMessage.array() );// 20250910 npe
    			}
    			if( !active) break;
    			
    			lastActivity = System.currentTimeMillis();

    			// (DEBUG 레벨일 경우) 메시지수신 로그
    			if ( getTraceLevel() >= DiagLogger.DEBUG ) {
                    logger.debug( CommonLib.getMessage("BDCEAIASI001", new String[]{context.getAdapterName(), "RECV", CommonLib.getTimestamp(), socketInfo, CommonLib.getDumpMessage(incomingMessage.array())}));
                }
    			try {
					if ( adapter.getContext().getLlFieldLength() > 0 ){
						int ll_len = adapter.getContext().getLlFieldLength();
						byte[] ll_fld = new byte[ll_len];
						System.arraycopy(incomingMessage.array(), adapter.getContext().getLlFieldIndex(), ll_fld, 0, adapter.getContext().getLlFieldLength());
						if ( Integer.parseInt(new String(ll_fld)) == 0 ) continue;
						// polling 메세지 처리
						if ( adapter.getContext().isUsePollMsg() ){
							
							int msglen = Integer.parseInt(new String(ll_fld));
							pollingMessage = ByteBuffer.allocate(msglen);
							try {
				    			processReadMessage( pollingMessage.array() );
							} catch (Exception e) {
								logger.error( e.getMessage(), e);
							}
							//logger.debug("[IOboundServer][run()]polling Msg-->" + new String(pollingMessage.array()));
							String pollmsg = new String(pollingMessage.array()); 
							if ( pollmsg.startsWith("REQPOLL") || pollmsg.startsWith("HDRREQPOLL")){
								byte[] resPoll = new byte[ll_len+msglen];
								System.arraycopy(incomingMessage.array(), 0, resPoll, 0, ll_len);
								System.arraycopy(pollingMessage.array(), 0, resPoll, ll_len, msglen);
								if ( resPoll[ll_len+2] == 'Q' )
									resPoll[ll_len+2] = 'S';
								if ( resPoll[ll_len+5] == 'Q' )
									resPoll[ll_len+5] = 'S';
						        Socket socket = socketChannel.socket();
								DataOutputStream dout = new DataOutputStream(socket.getOutputStream());
								dout.write(resPoll, 0, resPoll.length);
//								logger.debug("[IOboundServer][run()]resPoll Msg-->" + new String(resPoll));
								continue;
							}
						}
					}
				} catch (Exception e) {
					logger.error( e.getMessage(), e);
				}

				doResposeRecieve();

    			// Socket REUSE 모드가 아니라면 Connection Close
                if ( !isSocketReuse() ) {
                    active = false;
                    closeChannel();
                }
            } catch (SocketTimeoutException ex) {
            	checkRequest();
            	long idleTimeOutMin = context.getSessionTimeout(); 
            	if ((idleTimeOutMin > 0) && this.idle(idleTimeOutMin * 60 * 1000)){
                	logger.debug( "IOBoundServer(" + this.getName() + "), SessionTimeout :" + context.getSessionTimeout()
                			      + ", timeout :" + context.getTimeout());
                    active = false;
            	}
            	continue;
    		} catch( Exception e ) {
    			String msgEOF = ExceptionUtil.getErrorCode("BECEAIFJM010");
    			if ( !e.getMessage().equals(msgEOF)){
                    String errMsg = CommonLib.getMessage("BECEAIASI002", new String[]{context.getAdapterName(), "processReadMessage", e.getMessage(), "수신메시지", getReadingMessage() } );
                    if ( errMsg.length() > 0 ) {
                        logger.error( errMsg , e);

                    }
    			}
                active = false;

                continue;
    		}
    	}	// end of active

    	// LOOP을 빠져나오면 (active가 아닌 경우), Channel 을 Close 한다.
        try {
            closeChannel();
        } catch( Throwable e ) {}

    	SocketAdapterManager.getInstance().removeConnection( this );

        logger.info( CommonLib.getMessage("BICEAIASI003", new String[]{ context.getAdapterName(), socketInfo, Thread.currentThread().getName() }) );
        proxy.quiesceShutdown(this);
        SocketAdapterManager.getInstance().removeConnection( this );

        interrupt();
    }

	public SocketChannel getSocketchannel() {
		return socketChannel;
	}

	public void setSocketchannel(SocketChannel socketchannel) {
		this.socketChannel = socketchannel;
	}

    public String toString() {
        boolean status = true;
        StringBuffer strBuff = new StringBuffer();
        strBuff.append(context.getAdapterGroupName()).append(",");
        strBuff.append(context.getAdapterName()).append(",");
        strBuff.append(context.getBwkClsCd()).append(",").append(context.getBoundUsage()).append(",");
        strBuff.append(context.getSocketType()).append(",");
        strBuff.append(context.getResponseType()).append(",");
        try {
            strBuff.append( getCurrentSocket().getLocalAddress().getHostAddress()).append(":").append(getCurrentSocket().getLocalPort()).append(",");
        } catch( Throwable e ) {
            status = false;
            strBuff.append("?:?,");
        }

        try {
            strBuff.append( getCurrentSocket().getInetAddress().getHostAddress()).append(":").append(getCurrentSocket().getPort()).append(",");
        } catch( Throwable e ) {
            status = false;
            strBuff.append("?:?,");
        }

        strBuff.append( status ).append(",");
        strBuff.append( CommonLib.getCurrentTime( this.firstActivity )).append(",");
        strBuff.append(CommonLib.getCurrentTime( this.lastActivity ));

        return strBuff.toString();
    }

    private void doResposeRecieve(){

    	String strUUID = null;

        //----------------------------------------------------------------
		//BatchMsgDoc 생성
		batchMsgDoc = EAIBatchMsgManager.createBatchMsgWithUUID(true);  //true:초기화함

		//BatchMsgDoc Layer, SubLayer, StartTime 설정
		EAIBatchMsgManager.updateBatchMsgWithStageTime(batchMsgDoc, CommonKeys.LAYER_SOCKET_SERVER, CommonKeys.SUB_LAYER_SOCKET_SERVER);

		try {

            if (adapter.getRqstRspnsDstcd().equalsIgnoreCase("A")) {
                // 응답수신 셋팅
                batchMsgDoc.getBatchMsg().getHeader().setProcessType(CommonKeys.PROCESS_RESPONSE_RECEIVE);
            } else {
                // 응답송신 셋팅
                batchMsgDoc.getBatchMsg().getHeader().setProcessType(CommonKeys.PROCESS_RESPONSE_SEND);
            }
			logger.info("[IOboundServer]  ProcessCode >> " + adapter.getBatchProcessCode());
			ArrayList<OutsideVO> osd_array = OutsideManager.getInstance().getOutsideInfo(adapter.getBatchProcessCode());
			int i=0;
			for (i=0; i<osd_array.size(); i++) {
				OutsideVO tmpVO = osd_array.get(i);

				if (tmpVO.getOsdCode().equalsIgnoreCase(adapter.getBatchInstitutionCode())) {
					break;
				}
			}
			OutsideVO   outside = null;
			if (i==osd_array.size()) {
				String errMsg = "[IOboundServer] 대외기관 정보를 구할 수  없습니다.  배치업무코드 [" + adapter.getBatchProcessCode()+"] 대외기관["+adapter.getBatchInstitutionCode()+"]";
				batchMsgDoc.getBatchMsg().getBody().setErrorCode(99);
				batchMsgDoc.getBatchMsg().getBody().setErrorMsg(errMsg);
				throw new Exception(errMsg);
			} else {
                logger.info("OUSIDE INFO index [" + i + "]");
				outside = osd_array.get(i);
			}

			// BatchMsg 에 기본값 지정..
			batchMsgDoc.getBatchMsg().getHeader().setProcessCode(adapter.getBatchProcessCode());
			batchMsgDoc.getBatchMsg().getHeader().setProcessName(adapter.getBatchProcessName());
			batchMsgDoc.getBatchMsg().getHeader().setInstitutionCode(adapter.getBatchInstitutionCode());
			batchMsgDoc.getBatchMsg().getHeader().setInstitutionName(adapter.getBatchInstitutionName());
//			batchMsgDoc.getBatchMsg().getHeader().setInstituaionType(adapter.getBatchInstitutionType());
			batchMsgDoc.getBatchMsg().getBody().setPortNo(adapter.getBatchServerPortNo());
			batchMsgDoc.getBatchMsg().getBody().setTimeoutInterval(Integer.toString(adapter.getBatchInterMsgTimeout()));
			batchMsgDoc.getBatchMsg().getHeader().setFlowCode(adapter.getBatchRcvFlowRuleCode());
			batchMsgDoc.getBatchMsg().getHeader().setSystemConnCode(adapter.getBatchSystemConnCode());
			batchMsgDoc.getBatchMsg().getHeader().setRuleCode(adapter.getBatchRcvFlowRuleCode());
			RuleInfoVO vo = RuleInfoManager.getInstance().getRuleInfo(adapter.getBatchRcvFlowRuleCode());
			batchMsgDoc.getBatchMsg().getHeader().setRuleDesc((vo!=null)? vo.getDesc() : "Rule Code not found in the TSEAIBR02");
			String recvdMsg = new String(incomingMessage.array());
			if ( adapter.getContext().isUsePollMsg() ){
				recvdMsg = new String(incomingMessage.array()) + new String(pollingMessage.array());
			}
			batchMsgDoc.getBatchMsg().getBody().setRecvedMsg(recvdMsg);

			String strPathName = BatchDirUtil.getResponseRealDir();
			if ( strPathName.charAt(strPathName.length()-1) != '/' ) {
			strPathName = strPathName + '/';
			}
			BatchTargetVO btVO = FlowControllerManager.getInstance().getBatchTargetInfo(outside.getBatchCode(), outside.getOsdCode());
			StringBuffer sb = new StringBuffer();

			sb.append(btVO.getProcessCode());
			sb.append("/");
			sb.append(btVO.getOrganCode());
			strPathName = strPathName + sb.toString();
			logger.debug("[응답수신] PATH NAME = [" + strPathName + "]");
			batchMsgDoc.getBatchMsg().getHeader().setFilePath(strPathName);

            batchMsgDoc.getBatchMsg().getHeader().setUserID(adapter.getLnkID());
            batchMsgDoc.getBatchMsg().getHeader().setUserPassword(adapter.getLnkPwd());
            batchMsgDoc.getBatchMsg().getHeader().setBlockSize(outside.getBlkSize()); //TSEAIBJ06에 필드추가
            batchMsgDoc.getBatchMsg().getHeader().setSequenceSize(outside.getSequenceSize()); //TSEAIBJ06에 필드추가
            batchMsgDoc.getBatchMsg().getHeader().setPacketSize(outside.getPacketSize()); // 20060411 추가
            batchMsgDoc.getBatchMsg().getHeader().setRemoteIP(context.getHostName());
            batchMsgDoc.getBatchMsg().getHeader().setPort(context.getPortNumber()+"");
            //----------------------------------------------------------------
            logger.info("**** USER ID > [" + batchMsgDoc.getBatchMsg().getHeader().getUserID());
            logger.info("**** PASS WD > [" + batchMsgDoc.getBatchMsg().getHeader().getUserPassword());
            logger.info("**** BLOCK   > [" + batchMsgDoc.getBatchMsg().getHeader().getBlockSize());
            logger.info("**** SEQ SIZ > [" + batchMsgDoc.getBatchMsg().getHeader().getSequenceSize());
            logger.info("**** PACKET  > [" + batchMsgDoc.getBatchMsg().getHeader().getPacketSize());


			//단계 종료시간 설정
			batchMsgDoc.getBatchMsg().getBody().setPhaseEndTime(CalendarUtil.getCurrentTimeNoDash());

			//응답수신에 대한 최초 DB로그. StartLog 호출.
			LogUtil.setStartLog(batchMsgDoc);

	        strUUID = batchMsgDoc.getBatchMsg().getHeader().getUUID();
	        
	        // BatchRunningJobManager 에 Running Job 등록
	        logger.info("IOboundServer : BatchRunningJobManager 에 응답송수신 작업 등록......");
	        // 기관별 로그
	        Logger.addInstLog(batchMsgDoc);

	        BatchRunningJobManager.getInstance().addRunningJobInfo(strUUID, this, batchMsgDoc);
            logger.info("IOboundServer : FlowController JPD 호출 시작......");
            ResponseHandler handler = new ResponseHandler();
            this.batchMsgDoc = handler.execute(this.batchMsgDoc);
            logger.info("IOboundServer : FlowController JPD 호출 완료 !!");
            String endComp = this.batchMsgDoc.getBatchMsg().getPhaseinfo().getPhaseType();
            if ( !"END".equals( endComp ) ) {
            	logger.info( "FlowController JPD 호출결과 정상 종료가 아님 --> 소켓 연결 종료" );
            	socketChannel.close();
            }

		} catch (Exception ex) {
			try {
				// 파일로그 처리
				String errMsg = ExceptionUtil.getErrorCode(ex, "BECEAIASI010", new String[] {batchMsgDoc.getBatchMsg().getHeader().getUUID()});
				logger.error(errMsg, ex);   //응답수신 Socket Server 배치메시지 생성 및 정보 설정시 오류가 발생하였습니다. [UUID: {1}]

				// DB로그 처리
				batchMsgDoc.getBatchMsg().getBody().setPhaseEndTime(CalendarUtil.getCurrentTimeNoDash());
				LogUtil.setErrorLog(batchMsgDoc, errMsg);

			} catch (Exception e) {
				logger.error("[Socket Server] ★★★★★ 응답수신 Socket Server 예외 처리 중 에러 !! ★★★★★", e);
			}
        } finally {
            // BatchRunningJobManager 에서 Running Job 제거
            logger.info("IOboundServer : BatchRunningJobManager 에서 응답송수신 작업 제거......");
            BatchRunningJobManager.getInstance().removeRunningJobInfo(strUUID);
			lastActivity = System.currentTimeMillis();
        }
    }

	private void checkRequest(){
		
		if ( context.isResponseOnly()) return;
		
    	String processCode 		= context.getAdapterVO().getBatchProcessCode();
    	String institutionCode 	= context.getAdapterVO().getBatchInstitutionCode();
    	SchedulerMessageVO info;
    	
    	while ( true ){
        	try{
        		info = SchedulerMessageManager.getInstance().getExecutableJobFromQueue(processCode, institutionCode );
        		if ( info == null ) {
        			return;
        		}
        		
        		info.setSystemConnCode("this");

        		//해당 작업을 Job_Queue 테이블에서 Job_Processing 테이블로 이동
        		SchedulerMessageManager.getInstance().moveJobQueueToHandle(info);

        		//BatchMsgDoc 생성
        		batchMsgDoc = EAIBatchMsgManager.createBatchMsg(true);  //true:초기화함

        		//BatchMsgDoc Layer, SubLayer, StartTime 설정
        		EAIBatchMsgManager.updateBatchMsgWithStageTime(batchMsgDoc, CommonKeys.LAYER_SCHEDULER, CommonKeys.SUB_LAYER_SCHEDULER_PROCESSING);

        		//BatchMsgDoc 값 설정
        		batchMsgDoc.getBatchMsg().getHeader().setUUID(info.getUUID());
        		batchMsgDoc.getBatchMsg().getHeader().setProcessCode(info.getProcessCode());
        		batchMsgDoc.getBatchMsg().getHeader().setProcessName(info.getProcessName());
        		batchMsgDoc.getBatchMsg().getHeader().setProcessType(info.getProcessType());
        		batchMsgDoc.getBatchMsg().getHeader().setInstitutionCode(info.getInstitutionCode());
        		batchMsgDoc.getBatchMsg().getHeader().setInstitutionName(info.getInstitutionName());
        		batchMsgDoc.getBatchMsg().getHeader().setScheduleCode(info.getScheduleCode());
        		batchMsgDoc.getBatchMsg().getHeader().setScheduleSTime(info.getStartTime());
        		batchMsgDoc.getBatchMsg().getHeader().setScheduleETime(info.getEndTime());
        		batchMsgDoc.getBatchMsg().getHeader().setFilePath(info.getFilePath());
        		batchMsgDoc.getBatchMsg().getHeader().setFileName(info.getFileName());
        		batchMsgDoc.getBatchMsg().getHeader().setRenamedFileName(info.getRenamedFileName());
        		batchMsgDoc.getBatchMsg().getHeader().setJobCode(info.getJobCode());
        		batchMsgDoc.getBatchMsg().getHeader().setBizCode(info.getBizCode());
        		batchMsgDoc.getBatchMsg().getHeader().setFlowCode(info.getFlowRuleCode());
        		batchMsgDoc.getBatchMsg().getHeader().setRuleCode(info.getFlowRuleCode());
        		batchMsgDoc.getBatchMsg().getHeader().setInstitutionName(info.getInstitutionName());
//        		batchMsgDoc.getBatchMsg().getHeader().setInstituaionType(info.getInstitutionType());
        		batchMsgDoc.getBatchMsg().getHeader().setBlockSize(info.getBlockSize());
        		batchMsgDoc.getBatchMsg().getHeader().setSequenceSize(info.getSequenceSize());
        		batchMsgDoc.getBatchMsg().getHeader().setPacketSize(info.getPacketSize());
                batchMsgDoc.getBatchMsg().getHeader().setUserID(adapter.getLnkID());
                batchMsgDoc.getBatchMsg().getHeader().setUserPassword(adapter.getLnkPwd());
                batchMsgDoc.getBatchMsg().getHeader().setRemoteIP(context.getHostName());
                batchMsgDoc.getBatchMsg().getHeader().setPort(context.getPortNumber()+"");
        		batchMsgDoc.getBatchMsg().getHeader().setSystemConnCode(info.getSystemConnCode());
//        		batchMsgDoc.getBatchMsg().getHeader().setProtocol("TCP/IP");
        		batchMsgDoc.getBatchMsg().getHeader().setRequestResponse(info.getRqstRspnsDstcd());
        		batchMsgDoc.getBatchMsg().getHeader().setHdrInfoName(info.getHdrInfoName());
        		RuleInfoVO vo = RuleInfoManager.getInstance().getRuleInfo(info.getFlowRuleCode());
        		batchMsgDoc.getBatchMsg().getHeader().setRuleDesc((vo != null)? vo.getDesc() : "Rule Code not found in the TSEAIBR02");

        		// 레코드 크기 추가 2009.02.03
        		String jobCode = batchMsgDoc.getBatchMsg().getHeader().getJobCode();
                BatchJobInfoVO bjvo = DirInfoManager.getInstance().getFileInfo( jobCode );
                batchMsgDoc.getBatchMsg().getHeader().setRecLen((int)bjvo.getFileRecSize());
                
                // 20120601 추가 -- 시작
                if ( info.getProcessType().equals(CommonKeys.PROCESS_REQUEST_SEND) ||
                		info.getProcessType().equals(CommonKeys.PROCESS_RESPONSE_SEND ) ){
                    String hdrInfoName = info.getHdrInfoName();
                    batchMsgDoc.getBatchMsg().getHeader().setHdrInfoName(hdrInfoName);
                    batchMsgDoc.getBatchMsg().getHeader().setTotRecCnt(StringUtil.getTotRecCountFromHeader(hdrInfoName));
                    batchMsgDoc.getBatchMsg().getHeader().setBaseDate(StringUtil.getBaseDateFromHeader(hdrInfoName));
                    batchMsgDoc.getBatchMsg().getHeader().setFileSize(batchMsgDoc.getBatchMsg().getHeader().getRecLen() * batchMsgDoc.getBatchMsg().getHeader().getTotRecCnt());
                }
                // 20120601 추가 -- 여기까지

        		//재처리 플래그 설정..
        		if (info.getRecvRetryFlag().equals("1")){
        			batchMsgDoc.getBatchMsg().getHeader().setReqSendRetryFlag(true);	
        			logger.debug("[스케쥴 핸들러] ■ 요구송수신 JPD 호출: UUID ["+info.getUUID()+"]의 RetryFlag 를 true로 설정합니다." );	
        			
        		}else {
        			batchMsgDoc.getBatchMsg().getHeader().setReqSendRetryFlag(false);
        			logger.debug("[스케쥴 핸들러] ■ 요구송수신 JPD 호출: UUID ["+info.getUUID()+"]의 RetryFlag 를 false로 설정합니다." );		
        		}


        		batchMsgDoc.getBatchMsg().getBody().setSubUUID(info.getSubUUID());
        		batchMsgDoc.getBatchMsg().getBody().setSubLayerCode(CommonKeys.SUB_LAYER_SCHEDULER_PROCESSING);

        		try {
            		LogUtil.updateLogMaster(batchMsgDoc);
				} catch (Exception e) {
				}

                logger.info("[IOboundServer] ■ BatchRunningJobManager 등록완료 ");
                String strUUID = batchMsgDoc.getBatchMsg().getHeader().getUUID();
                
                // BatchRunningJobManager 에 Running Job 등록
                logger.info("IOboundServer : BatchRunningJobManager 에 응답송수신 작업 등록......");
                BatchRunningJobManager.getInstance().addRunningJobInfo(strUUID, this, batchMsgDoc);

                try {
                    //===================================================
                    logger.info("IOboundServer : FlowController JPD 호출 시작......");
                    ResponseHandler handler = new ResponseHandler();
                    this.batchMsgDoc = handler.execute(this.batchMsgDoc);
                    logger.info("IOboundServer : FlowController JPD 호출 완료 !!");
                    String endComp = this.batchMsgDoc.getBatchMsg().getPhaseinfo().getPhaseType();
                    if ( !"END".equals( endComp ) ) {
                    	logger.info( "FlowController JPD 호출결과 EEND 소켓 연결 종료" );
                    	socketChannel.close();
                    }
                    //===================================================
                    
                } finally {
                    // BatchRunningJobManager 에서 Running Job 제거
                    logger.info("IOboundServer : BatchRunningJobManager 에서 응답송수신 작업 제거......");
                    BatchRunningJobManager.getInstance().removeRunningJobInfo(strUUID);
        			lastActivity = System.currentTimeMillis();
                }
        	} catch ( Exception e){
        		return;
        	}
    	}
    }
    public void processReadMessage( byte[] buffer ) throws Exception {
        if (buffer == null || buffer.length == 0) throw new Exception("");
        
        int readBytes = 0;
        boolean isEOF = false;
        Socket socket = socketChannel.socket();
        DataInputStream din = new DataInputStream( socket.getInputStream());
        int len = buffer.length;
        int timeOut = (int)getTimeout();

        if ( timeOut < 1000 ) {
        	timeOut = 1000;
        }
        if ( timeOut > 60000 ) {
        	timeOut = 60000;
        }
        
        logger.info( "[IOboundServer][" + context.getAdapterName() + "]데이터 수신 대기 중(타임아웃:" + timeOut + ")");
        socket.setSoTimeout( timeOut );
        
        while (readBytes < len) {
            try {
                readBytes += din.read(buffer, readBytes, len-readBytes);
                if (readBytes < 0) {
                	isEOF = true;
                	break;
                }
                
            } catch (SocketTimeoutException ex) {
            	throw ex;
            } catch (Exception ex) {  //throws IOException, NullPointerException, IndexOutOfBoundsException 
                active = false;
                return;
            }
        }

        if ( isEOF ) {
            String errMsg = ExceptionUtil.getErrorCode("BECEAIFJM010");
            throw new Exception(errMsg);  //대외기관으로부터 전문 수신 시 End-Of-Stream 에 도착하여 읽어들일 데이터가 없습니다. 해당 대외기관에 연락바랍니다.
        }

    } // end of readData
    private boolean isSocketReuse() {
    	return this.context.getSocketReuse().equals( ConfigurationContext.TRUE_FLAG );
    }
    private synchronized void closeChannel() throws IOException {

        if(socketChannel != null ) {
        	socketChannel.socket().close();
        	socketChannel.close();
        }
        socketChannel = null;
    } //
    private String  getReadingMessage() {
        String rMsg = "";
        if ( incomingMessage != null && incomingMessage.position() > 0 ) {
            byte[] dMsg = new byte[ incomingMessage.position() ];
            System.arraycopy( incomingMessage.array(), 0, dMsg, 0, dMsg.length );
            rMsg = CommonLib.getDumpMessage( dMsg );
        }
        return rMsg;
    }

}
