package com.eactive.eai.adapter.wca; import java.io.BufferedOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; import java.net.SocketException; import java.net.SocketTimeoutException; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import com.eactive.eai.adapter.AdapterManager; import com.eactive.eai.adapter.AdapterPropManager; import com.eactive.eai.adapter.AdapterVO; import com.eactive.eai.adapter.wca.cfg.SNAAdapter; import com.eactive.eai.adapter.wca.cfg.SNAAdapterManager; import com.eactive.eai.adapter.wca.cfg.SessionGroupDataEx; import com.eactive.eai.adapter.wca.data.AppCodeCmd; import com.eactive.eai.adapter.wca.data.ManualBackupCmd; import com.eactive.eai.adapter.wca.data.WCAAdapterInfoCmd; import com.eactive.eai.adapter.wca.data.WCAHeader; import com.eactive.eai.adapter.wca.data.WCAQueue; import com.eactive.eai.adapter.wca.data.WCAQueueData; import com.eactive.eai.adapter.wca.exception.WCAException; import com.eactive.eai.adapter.wca.global.WCADefine; import com.eactive.eai.adapter.wca.util.CodeCvrt; import com.eactive.eai.adapter.wca.util.MyLog; import com.eactive.eai.adapter.wca.util.MyUtil; import com.eactive.eai.common.errorcode.ErrorCodeHandler; import com.eactive.eai.common.property.PropManager; import com.eactive.eai.common.util.LogKeys; import com.eactive.eai.common.util.Logger; import com.eactive.eai.common.util.SMSLogUtil; /** * 1. 기능 : Softlink TCP 세션 연결 및 수신 데이타를 처리한다. * 2. 처리 개요 : * - * 3. 주의사항 * * @author : * @version : v 1.0.0 * @see : * @since : 2005. 6. 17. 오후 10:01:13 */ public class WCASessionThread implements Runnable { /** * SNAAdapter critical한 정보 로깅을 위한 logger */ Logger adapter_logger = Logger.getLogger(WCADefine.ADAPTER_LOGGER_NAME); // 20090810 Start private String sNodeName = ""; // Softlink Node Name // 20090810 End private Socket sockSoftLink = null; // SoftLink와 연결할 Socket //private BufferedInputStream isSoftLink = null; // Socket에 대한 InputStream private InputStream isSoftLink = null; // Socket에 대한 InputStream private BufferedOutputStream osSoftLink = null; // Socket에 대한 OutputStream private HashMap hmapRcvData = null; // 세션에서 수신된 데이터를 저장할 Queue에 대한 HashMap private MyLog myLog = null; // 메시지 로그 처리 오브젝트 private MyLog myTrc = null; // 트레이스 처리 오브젝트 private String sIpAddr = null; // SoftLink IP 주소 private int nPortNo = 0; // SoftLink Port 번호 private String sAdapterGroupName = null; // SoftLink 세션에 대한 Adapter Group Name private String sAdapterName = null; // SoftLink 세션에 대한 Adapter Name private String sGroupCode = null; // SoftLink 세션에 대한 Group Code private int nSessId = 0; // SoftLiInk 세션 ID private WCAEventInterface wcaEventHandler = null; // SoftLiInk 세션에 대한 수신 데이터 처리 이벤트 핸들러 private int nRcvTimeout = 0; // 데이터 수신 Timeout private int nConnTimeout = 0; // 세션 연결 Timeout private int nSessStat = 0; // TCP 세션 상태 0 : 연결안됨, 1 : TCP 세션 연결, 2 : TCP 세션 사용중 (사용안함) private int nDisconnectCnt = 0; // 세션 해제 횟수 private int nContinuousDisconnectCnt = 0; // 연속적으로 세션 연결 실패 횟수 private int nSndCnt = 0; // 데이터 송신 횟수 private int nRcvCnt = 0; // 데이터 수신 횟수 private boolean bRunning = false; // Thread 동작 여부 private boolean bBackupSessionPool = false; // Backup 세션 여부 // Softlink IP 주소가 여러개인 경우, 백업 모드 기능 자체를 사용할 수 없음 private boolean bBackupEnableFlag = true; // Backup 세션 전환 사용 가능 여부 private boolean bBeforeConn = false; // 이전 TCP 세션 연결 여부 private int tran_timeout = WCADefine.DEFAULT_TRANSACTION_TIMEOUT ; // 트랜잭션 타임아웃 private String tran_mode; // 송신(S),수신(R) 모드 long lReadStartTime = 0L, lReadEndTime = 0L, lNotifyEndTime = 0L; private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd=HH:mm:ss.SSS"); private SNAAdapter snaAdapter = null; // 20090810 public boolean getBackupEnableFlag() { return bBackupEnableFlag; } public void setBackupEnableFlag(boolean bBackupEnableFlag) { this.bBackupEnableFlag = bBackupEnableFlag; return; } // 20090810 End /** * 1. 기능 : 노드 이름 설정 * 2. 처리 개요 : * 3. 주의사항 * * @param sNodName 노드이름 **/ public void setNodeName(String s_node_name) { if (s_node_name == null) { s_node_name = ""; } this.sNodeName = s_node_name.trim(); } /** * 1. 기능 : 노드 이름 반환 * 2. 처리 개요 : * 3. 주의사항 * * @return 노드이름 **/ public String getNodeName() { return this.sNodeName; } /** * 1. 기능 : 세션 정보 반환 * 2. 처리 개요 : * 3. 주의사항 * * @return 세션 정보 **/ public String toString() { StringBuffer sb_name = new StringBuffer(); sb_name.append(" " + sGroupCode + "-" + nSessId); if (bBackupSessionPool) { sb_name.append(":BACKUP "); } else { sb_name.append(" "); } return sb_name.toString(); } /** * 1. 기능 : INBOUND 핸들러 등록 * 2. 처리 개요 : * 3. 주의사항 **/ public void registerEventHandler(Object objHandler) { wcaEventHandler = (WCAEventInterface)objHandler; return; } /** * 1. 기능 : 트랜잭션 타임아웃 설정 * 2. 처리 개요 : * 3. 주의사항 * * @param timeout 트랜잭션 타임아웃 **/ public void setTranTimeout(int timeout) { this.tran_timeout = timeout; } /** * 1. 기능 : 트랜잭션 타임아웃 반환 * 2. 처리 개요 : * 3. 주의사항 * * @return 트랜잭션 타임아웃 **/ public int getTranTimeout() { return this.tran_timeout; } /** * 1. 기능 : 트랜잭션 송수신 모드 설정 * 2. 처리 개요 : * 3. 주의사항 * * @param sTranMode 트랜잭션 송수신 모드 **/ public void setTranMode(String sTranMode) { if (sTranMode == null ) { sTranMode = ""; } this.tran_mode = sTranMode; } /** * 1. 기능 : 트랜잭션 송수신 모드 반환 * 2. 처리 개요 : * 3. 주의사항 * * @return 트랜잭션 송수신 모드 **/ public String getTranMode() { return this.tran_mode; } /** * 1. 기능 : Sotlink 세션 정보 설정 * 2. 처리 개요 : * 3. 주의사항 * * @param sIpAddr Softlink Ip 주소 * @param nPortNo SoftLink Port 번호 * @param nSessNum WCA 세션 수 **/ public void setSessionInfo(String sIpAddr, int nPortNo) { this.sIpAddr = sIpAddr; this.nPortNo = nPortNo; } public void updateSessionInfoEx(SessionGroupDataEx sessgroup) { // 로컬 세션인 경우 if (!isBackupSessionPool()) { setSessionInfo(sessgroup.getSoftLinkSevrName(), sessgroup.getPort()); } // 백업 세션인 경우 else { setSessionInfo(sessgroup.getBackupNodeName(), sessgroup.getBackupPort()); } setLogInfo(sessgroup.isLogWritable(), sessgroup.getLogLevel(), sessgroup.getLogSize()); setTranTimeout(sessgroup.getTranTimeout()); setBackupEnableFlag(sessgroup.getBackupEnableFlag()); // APP_CODE 프라퍼티가 변경되었을 경우, Softlink에게 데이터 전송 try { sendWcaSessionAppCode(true); } catch (Exception e) { adapter_logger.warn("WCASessionThread:updateSessionInfoEx> Exception Msg = " + e.getMessage()); } myLog.logMsg(MyLog.INFO, toString() + " 세션 정보 갱신 " + sessgroup.toString()); } // 2020.05.27 updateSessionInfoEx 함수를 참조하여 개발함 public void updateWcaAppCodeEx() { // APP_CODE 프라퍼티가 변경되었을 경우, Softlink에게 데이터 전송 try { adapter_logger.warn("WCASessionThread:updateWcaAppCodeEx> Try to Send Wca AppCode"); sendWcaSessionAppCode(false); } catch (Exception e) { adapter_logger.warn("WCASessionThread:updateWcaAppCodeEx> Exception Msg = " + e.getMessage()); } myLog.logMsg(MyLog.INFO, toString() + " WCA APP CODE 정보 갱신"); } /** * 1. 기능 : 로그 설정 * 2. 처리 개요 : * 3. 주의사항 * * @param bLogYN 로깅 여부 * @param nLogLevel 로깅 레벨 * @param nLogSize 로깅 파일 사이즈 **/ public void setLogInfo(boolean bLogYN, int nLogLevel, int nLogSize) { if (myLog != null) { myLog.setLogLevel(nLogLevel); myLog.setTraceOnOff(bLogYN); myLog.setMaxLogFileSize(nLogSize); } if (myTrc != null) { myTrc.setLogLevel(nLogLevel); myTrc.setTraceOnOff(bLogYN); myTrc.setMaxLogFileSize(nLogSize); } } /** * 1. 기능 : SoftLink와의 세션을 관리할 쓰레드 클래스 생성 함수 * 2. 처리 개용 : * - 파라미터로 넘어온 정보를 내부 변수에 설정한다. * - 로그와 트레이스를 저장하기 위한 로그 처리 클래스의 오브젝트를 생성한다. * 3. 주의사항 * - 트레이스 처리의 동기화를 위해서 myTrc 클래스에 대한 동기화를 수행한다. * - 송신 데이터 버퍼 형식 : 길이(4) + Data(n) * * @param sIpAddr Softlink Ip 주소 * @param nPortNo SoftLink Port 번호 * @param sAdapterGroupName 어댑터 그룹 이름 * @param sAdapterName 어댑터 이름 * @param sGroupCode LU 그룹 이름 * @param nSessId Pool에 설정된 세션 수 * @param bBackupSessionPool Backup Pool 여부 (true: 백업 세션) * @param bLogYN 로깅 여부 * @param nLogLevel 로그 레벨 * @param nLogSize 로그 파일 사이즈 */ public WCASessionThread(String sNodeName, String sIpAddr, int nPortNo, String sAdapterGroupName, String sAdapterName, String sGroupCode, int nSessId, boolean bBackupSessionPool, boolean bLogYN, int nLogLevel, int nLogSize) { try { this.sNodeName = sNodeName; this.sIpAddr = sIpAddr; this.nPortNo = nPortNo; this.sAdapterGroupName = sAdapterGroupName; this.sAdapterName = sAdapterName; this.sGroupCode = sGroupCode; this.nSessId = nSessId; this.bBackupSessionPool = bBackupSessionPool; nSessStat = WCADefine.SESS_STAT_NOTCONN; hmapRcvData = new HashMap(); nRcvTimeout = WCADefine.DEFAULT_RECEIVE_TIMEOUT; nConnTimeout = WCADefine.DEFAULT_CONNECT_TIMEOUT; snaAdapter = SNAAdapterManager.getInstance().selectSnaAdapter(sAdapterGroupName); String sLogDirectory = PropManager.getInstance().getProperty(LogKeys.LOGGER_INFO, LogKeys.LOG_DIRECOTRY_PREFIX); if (sLogDirectory==null || sLogDirectory.equals("")) { sLogDirectory = WCADefine.SERVER_NAME + File.separatorChar + "wca"; } else { sLogDirectory = sLogDirectory + File.separatorChar + WCADefine.SERVER_NAME + File.separatorChar + "wca"; } //if (trc_logger.isDebug()) trc_logger.debug(">> sLogDirectory = " + sLogDirectory); // 로그와 트레이스 처리를 위한 오브젝트 생성 String sMyTrcPath = ""; String sMyLogPath = ""; if (bBackupSessionPool) { // 20090810 Start /* myTrc = new MyLog(bLogYN, nLogLevel, nLogSize, sLogDirectory + File.separatorChar + sGroupCode + "-" + nSessId + "_BACKUP.trc"); myLog = new MyLog(bLogYN, nLogLevel, nLogSize, sLogDirectory + File.separatorChar + sGroupCode + "-" + nSessId + "_BACKUP.log"); sMyTrcPath = sLogDirectory + File.separatorChar + sGroupCode + "-" + nSessId + "_BACKUP.trc"; sMyLogPath = sLogDirectory + File.separatorChar + sGroupCode + "-" + nSessId + "_BACKUP.log"; */ myTrc = new MyLog(bLogYN, nLogLevel, nLogSize, sLogDirectory + File.separatorChar + sNodeName + "_" + sGroupCode + "-" + nSessId + "_BACKUP.trc"); myLog = new MyLog(bLogYN, nLogLevel, nLogSize, sLogDirectory + File.separatorChar + sNodeName + "_" + sGroupCode + "-" + nSessId + "_BACKUP.log"); sMyTrcPath = sLogDirectory + File.separatorChar + sNodeName + "_" + sGroupCode + "-" + nSessId + "_BACKUP.trc"; sMyLogPath = sLogDirectory + File.separatorChar + sNodeName + "_" + sGroupCode + "-" + nSessId + "_BACKUP.log"; // 200908010 End } else { // 20090810 Start /* myTrc = new MyLog(bLogYN, nLogLevel, nLogSize, sLogDirectory + File.separatorChar + sGroupCode + "-" + nSessId + ".trc"); myLog = new MyLog(bLogYN, nLogLevel, nLogSize, sLogDirectory + File.separatorChar + sGroupCode + "-" + nSessId + ".log"); sMyTrcPath = sLogDirectory + File.separatorChar + sGroupCode + "-" + nSessId + ".trc"; sMyLogPath = sLogDirectory + File.separatorChar + sGroupCode + "-" + nSessId + ".log"; */ myTrc = new MyLog(bLogYN, nLogLevel, nLogSize, sLogDirectory + File.separatorChar + sNodeName + "_" + sGroupCode + "-" + nSessId + ".trc"); myLog = new MyLog(bLogYN, nLogLevel, nLogSize, sLogDirectory + File.separatorChar + sNodeName + "_" + sGroupCode + "-" + nSessId + ".log"); sMyTrcPath = sLogDirectory + File.separatorChar + sNodeName + "_" + sGroupCode + "-" + nSessId + ".trc"; sMyLogPath = sLogDirectory + File.separatorChar + sNodeName + "_" + sGroupCode + "-" + nSessId + ".log"; // 20090810 End } /* 20080523 Start */ try { if (adapter_logger.isWarn()) { adapter_logger.warn("adapter_logger trc_logger Path : " + Logger.LOGGER_ADAPTER); adapter_logger.warn("adapter_logger adapter_logger Path : " + WCADefine.ADAPTER_LOGGER_NAME); adapter_logger.warn("adapter_logger myTrc Path : " + sMyTrcPath); adapter_logger.warn("adapter_logger myLog Path : " + sMyLogPath); } myLog.logMsg(MyLog.WARN, "trc_logger Path : " + Logger.LOGGER_ADAPTER); myLog.logMsg(MyLog.WARN, "adapter_logger Path : " + WCADefine.ADAPTER_LOGGER_NAME); myLog.logMsg(MyLog.WARN, "myTrc Path : " + sMyTrcPath); myLog.logMsg(MyLog.WARN, "myLog Path : " + sMyLogPath); } catch(Exception ignore) { // System.out.println("WCASessionThread> Exception Msg = " + ignore.toString()); } /* 20080523 End */ } catch(Exception e) { adapter_logger.error("WCASessionThread] - [" + WCAException.E_ETC + "] " + toString() + e.toString()); } } /** * 1. 기능 : 백업 세션 여부 설정 (true: 백업 세션) * 2. 처리 개요 : * 3. 주의사항 * * @param flag 백업 세션 여부 **/ public void setBackupSessionPool(boolean flag) { bBackupSessionPool = flag; } /** * 1. 기능 : 백업 세션 여부 반환 (true: 백업 세션) * 2. 처리 개요 : * 3. 주의사항 * * @return 백업 세션 여부 **/ public boolean isBackupSessionPool() { return bBackupSessionPool; } /** * 1. 기능 : 데이터 송신별 수신 데이터를 대기할 Queue를 등록 * 2. 처리 개요 : * - 송신 데이터의 트랜잭션 Key 필드를 기준으로 HashMap에 등록한다. * 3. 주의사항 * - WLI의 송신 쓰레드는 데이터 송신 후, 등록한 Queue를 대기한다. * * @param objKey HashMap에 저장될 unique한 key (UUID) * @param objData HashMap에 저장될 값 (송신에 대한 Queue 데이타) * @return 0 **/ public int registerRcvQueue(Object objKey, Object objData) { synchronized (hmapRcvData) { hmapRcvData.put(objKey, objData); } return 0; } /** * 1. 기능 : Queue에 등록된 송신에 대한 Queue 데이타 삭제 * 2. 처리 개요 : * 3. 주의사항 * * @param objKey HashMap에 저장될 unique한 key (UUID) **/ public int unregisterRcvQueue(Object objKey) { synchronized (hmapRcvData) { hmapRcvData.remove(objKey); } return 0; } /** * 1. 기능 : SoftLink 세션을 연결한다. * 2. 처리 개요 : * - SoftLink와 TCP 세션을 연결한다. * - 세션이 연결되면 소켓에 대한 In/Out 스트림을 생성한다. * 3. 주의사항 * * @param nTimeout 연결 Timeout * @return 세션 연결 결과 * @exception IOException */ public boolean connectSoftLink(int nTimeout) throws IOException { SocketAddress sockAddr = null; try { sockSoftLink = new Socket(); myLog.logMsg(MyLog.DEBUG, "connectSoftLink] New Socket is Created..."); sockAddr = new InetSocketAddress(sIpAddr, nPortNo); myLog.logMsg(MyLog.INFO, "connectSoftLink] New Socket Address, Addr = " + sockAddr); myLog.logMsg(MyLog.DEBUG, "connectSoftLink] Try Connect to SoftLink..., nTimeout = " + nTimeout + "ms"); sockSoftLink.connect(sockAddr, nTimeout); myLog.logMsg(MyLog.INFO, "RECVEIVE Buffer Size = " + sockSoftLink.getReceiveBufferSize()); //sockSoftLink.setReceiveBufferSize(2048); myLog.logMsg(MyLog.INFO, "connectSoftLink] Session is Connected...(Local Port = " + sockSoftLink.getLocalPort() + ")"); //isSoftLink = new BufferedInputStream(sockSoftLink.getInputStream()); isSoftLink = sockSoftLink.getInputStream(); osSoftLink = new BufferedOutputStream(sockSoftLink.getOutputStream()); myLog.logMsg(MyLog.INFO, "connectSoftLink] Socket In/Out Stream is Opened..."); // if true, pakcets are sent as quickly as possible regardless of their size sockSoftLink.setTcpNoDelay(true); nSessStat = WCADefine.SESS_STAT_READY; nContinuousDisconnectCnt = 0; return true; } catch (Exception e) { myLog.logMsg(MyLog.ERROR, "connectSoftLink] " + e.toString()); // softlink가 내려가고 EAI가 내려갔을 경우,,, 세션이 백션으로 가야함...(2분) if (nContinuousDisconnectCnt % WCADefine.DEFAULT_BACKUP_CONVERSION_CHECK == 0) { checkBackupConversion(); } nContinuousDisconnectCnt++; nDisconnectCnt++; return false; } } /** * 1. 기능 : Thread 종료 * 2. 처리 개요 : * - running 상태 Flag를 false로 설정한다. * 3. 주의사항 **/ public void stopAdapter() { myLog.logMsg(MyLog.INFO, "stopAdapter] Thread is Stopping. " + toString() ); bRunning = false; } /** * 1. 기능 : 어댑터 상태 설정 * 2. 처리 개요 : 어댑터 그룹 이용가능한 세션이 없을 경우 어댑터 상태를 false로 한다. * 3. 주의사항 **/ private void setAdapterStatus(boolean flag) { int nAdapterConnected; /* 20080523 수정 시작 */ /* 어댑터 상태를 사용안함으로 설정할때, EAI Framework쪽에서 어댑터 정보를 메모리에서 삭제하기 때문에 getAdapterVO 함수 호출시 NULL 값이 리턴되어 synchronized(av) 라인 처리시 java.lang.NullPointerException 발생함 --> 전체 로직을 try, catch로 묶음 */ try { AdapterManager amanager = AdapterManager.getInstance(); AdapterVO av = amanager.getAdapterVO(this.sAdapterGroupName,this.sAdapterName); synchronized (av) { // if (av.isStatus() == flag) //{ try { nAdapterConnected = snaAdapter.getConnectedSessNum(); if (av != null) { if (nAdapterConnected <= 0 ) { av.setStatus(false); } else { av.setStatus(true); } } } catch (Exception e) { adapter_logger.error("setAdapterStatus error", e); } //} } } catch (Exception e) { myLog.logMsg(MyLog.INFO, "setAdapterStatus] Exception Msg = " + e.toString()); } /* 20080523 수정 끝 */ } /** * 1. 기능 : 처리되지 않은 트랜잭션 출력 및 notify * 2. 처리 개요 : * 3. 주의사항 **/ private void traceRemainTransaction() { int iRemainWorkCnt = 0; String sKey = null; WCAQueue queueWSA = null; WCAHeader header = null; String sMessage = ""; String sCode = ""; char cMode ; boolean bRecvSendOK = false; Iterator iter = null; HashMap copy = (HashMap)hmapRcvData.clone(); iter = copy.keySet().iterator(); myLog.logMsg(MyLog.ERROR, ">>>>>>>>> " + toString() +" Remain Work is started. (Number = "+copy.size() + ") <<<<<<<<<<"); while (iter.hasNext()) { try { iRemainWorkCnt++; sKey = (String)iter.next(); if (sKey == null) { if (adapter_logger.isError()) { adapter_logger.error("traceRemainTransaction] " + toString() + "sKey is null"); } myLog.logMsg(MyLog.ERROR, "traceRemainTransaction] sKey is null"); continue; } myLog.logMsg(MyLog.ERROR, "Remain Work " + String.valueOf(iRemainWorkCnt) + "] TRANSACTION KEY = " + sKey); // notify synchronized (hmapRcvData) { queueWSA = (WCAQueue)hmapRcvData.remove(sKey); } synchronized (queueWSA) { bRecvSendOK = queueWSA.getRecvSendOKFlag(); cMode = queueWSA.getMode(); } if (bRecvSendOK) { sCode = WCAException.E_SOFTLINK_RECV_SESSION_CLOSE; } else { sCode = WCAException.E_SOFTLINK_SEND_SESSION_CLOSE; } if (adapter_logger.isError()) { adapter_logger.error(WCAException.displayError(sCode) + toString() + " TRANSACTION KEY = " + sKey); } sMessage = sCode + ErrorCodeHandler.getMessage(sCode); // 데이타 조립 header = new WCAHeader(); byte[] pBuff = new byte[WCAHeader.WCA_HEADER_LEN + sMessage.getBytes().length]; System.arraycopy(header.getHeader(), 0, pBuff, 0, WCAHeader.WCA_HEADER_LEN); System.arraycopy(sMessage.getBytes(), 0, pBuff, WCAHeader.WCA_HEADER_LEN, sMessage.getBytes().length); // NonResponse 모드이고 sendok를 받았으면 INBOUND로 보낸다. 그외는 notify if (cMode == (WCAHeader.TRAN_MODE_NONRESPONSE).charAt(0) && bRecvSendOK){ myLog.logMsg(MyLog.DEBUG, "traceRemainTransaction] NonResponse, send OK is received ... inbound"); byte[] pRecvBuff = queueWSA.getDataFromQueue(); System.arraycopy(pRecvBuff, 0, pBuff, 0, WCAHeader.WCA_HEADER_LEN); if (wcaEventHandler != null) { myLog.logMsg(MyLog.DEBUG, "traceRemainTransaction] Call Event Handler : handleTimeoutData()"); wcaEventHandler.handleNonRspData(sAdapterGroupName, sAdapterName, sGroupCode, pBuff.length, pBuff); } else { myLog.logMsg(MyLog.ERROR, "traceRemainTransaction] Event Handler is Not Registered, So Discard Data..."); } } else { synchronized (queueWSA) { WCAQueueData qdataWSA = new WCAQueueData(pBuff.length, pBuff); queueWSA.addDataToQueue(qdataWSA); myLog.logMsg(MyLog.DEBUG, "traceRemainTransaction] (START) Notify WLI Thread..."); queueWSA.notifyAll(); myLog.logMsg(MyLog.DEBUG, "traceRemainTransaction] (END) Notify WLI Thread..."); } } } catch (Exception e) { if (adapter_logger.isError()) { adapter_logger.error(WCAException.displayError(WCAException.E_INFORM_ERROR, sKey)); } } } } /** * 1. 기능 : 데이타 수신 대기 및 수신 데이타 처리 * 2. 처리 개요 : * - 세션이 연결될때까지 계속 socket 연결 시도한다. * - bRunning가 true 일 동안 계속 Socket InputStream을 read한다. * - 수신 데이타를 DATA TYPE에 따라 처리한다. * 3. 주의사항 **/ public void run() { int nRcvLen; byte[] pLenBuff = null; int nDataLen = 0; int nCheckOldWCAQueueCnt = 0; int nConnectedSessNum = 0; int nConfiguredSessNum = 0; myLog.logMsg(MyLog.INFO, "Transaction Timeout = " + tran_timeout + ", Transaction Mode = " + tran_mode); myLog.logMsg(MyLog.INFO, "run] " + toString() + " Thread is Started. (Thread Group Name = " + Thread.currentThread().getThreadGroup().getName() + ")"); //adapter_logger.debug(toString() + " Thread is Started. (Thread Group Name = " + Thread.currentThread().getThreadGroup().getName() + ")"); bRunning = true; while(true) { try { // Thread stop 시켰을 경우 종료한다. if (!bRunning) { myLog.logMsg(MyLog.DEBUG, "run] " + toString() + " bRunning = false so stop"); break; } // 1. Socket 연결 시도 if (nSessStat == WCADefine.SESS_STAT_NOTCONN) { if (bBackupSessionPool) { nConfiguredSessNum = snaAdapter.getConfiguredBackupSessNum(sNodeName, sGroupCode); nConnectedSessNum = snaAdapter.getConnectedBackupSessNum(sNodeName, sGroupCode); } else { nConfiguredSessNum = snaAdapter.getConfiguredNormalSessNum(sNodeName, sGroupCode); nConnectedSessNum = snaAdapter.getConnectedNormalSessNum(sNodeName, sGroupCode); } if (nConfiguredSessNum < nConnectedSessNum) { if (adapter_logger.isWarn()) { adapter_logger.warn("설정된 세션수보다 많은 세션수가 존재합니다. Thread 종료합니다.[" + nConnectedSessNum + "/" + nConfiguredSessNum + "]"); } myLog.logMsg(MyLog.WARN, "설정된 세션수보다 많은 세션수가 존재합니다. Thread 종료합니다.[" + nConnectedSessNum + "/" + nConfiguredSessNum + "]"); closeSoftLink(); break; } myLog.logMsg(MyLog.DEBUG, "run] Status = SESS_STAT_NOTCONN, So Retry to Connect To SoftLink...."); if (connectSoftLink(nConnTimeout) == false) { myLog.logMsg(MyLog.ERROR, "run] Can't Connect To SoftLink, Sleep " + WCADefine.DEFAULT_SESS_RECOVERY_GAP); if (bBeforeConn) { adapter_logger.error(WCAException.displayError(WCAException.E_SOFTLINK_NOTCONN,toString())); myLog.logMsg(MyLog.WARN, "run] Session is Closed "); bBeforeConn = false; /* 20080523 SMS 로그 추가 시작 */ try { int nSessCnt = snaAdapter.getConnectedNormalSessNum(sNodeName, sGroupCode); if (adapter_logger.isWarn()) { adapter_logger.warn("getConnectedNormalSessNum> " + sAdapterGroupName + ", " + sGroupCode + " = "+ nSessCnt); } myLog.logMsg(MyLog.WARN, "getConnectedNormalSessNum> " + sAdapterGroupName + ", " + sGroupCode + " = "+ nSessCnt); if (!bBackupSessionPool) { if (nSessCnt == 0) { // String strSmsMsg = sAdapterGroupName + " Session is Closed"; // String strSmsMsg = sGroupCode + " Session is Closed"; String strSmsMsg = "Session is Closed"; try { if (adapter_logger.isWarn()) { adapter_logger.warn("WCASessionThread:run> Log SMS Msg, Msg = " + sGroupCode + " " + strSmsMsg); } myLog.logMsg(MyLog.WARN, "WCASessionThread:run> Log SMS Msg, Msg = " + sGroupCode + " " + strSmsMsg); SMSLogUtil.loggingSMS(sGroupCode, strSmsMsg); } catch (Exception ignore) { myLog.logMsg(MyLog.DEBUG, "run] Exception, While Write SMS Log, Msg = " + ignore.toString()); } } } } catch (Exception ignore) { // System.out.println("WCASessionThread:run> Exception Msg = " + ignore.toString()); } /* 20080523 SMS 로그 추가 끝 */ } Thread.sleep(WCADefine.DEFAULT_SESS_RECOVERY_GAP * 1000); continue; } } // 세션이 복귀되면 adapter 상태를 변경한다. if (!bBeforeConn) { setAdapterStatus(false); sendAdapterStatusData(); // 20090810 Start sendWcaSessionAppCode(true); // 20090810 End } bBeforeConn = true; // Socket 수신 타임 아웃 설정 //sockSoftLink.setSoTimeout(WCADefine.DEFAULT_SOCK_RCV_TIMEOUT * 1000); // 2. Socket 수신 데이타 대기 -- 길이 필드 수신 (4 바이트) String dateString = formatter.format(ZonedDateTime.now()); lReadStartTime = System.currentTimeMillis(); pLenBuff = recvLenthField(WCADefine.LEGTH_FIELD_SIZE); if (pLenBuff == null) { // Connection is Close... closeSoftLink(); continue; } // 3. 길이 필드 변환 // 20090302 Start /* nDataLen = Integer.parseInt(new String(pLenBuff)); */ nDataLen = getInt(pLenBuff, 0); // 20090302 End myLog.logMsg(MyLog.INFO, "run] Data Length Field = " + nDataLen); if (nDataLen < 0) { myLog.logMsg(MyLog.ERROR, "run] Invalid Data Length Field... So Close Session"); closeSoftLink(); continue; } // 4. 데이타 수신 byte[] pDataBuff = recvDataField(nRcvTimeout, nDataLen); if (pDataBuff == null) { // Connection is Close... closeSoftLink(); continue; } lReadEndTime = System.currentTimeMillis(); if (adapter_logger.isDebug()) { adapter_logger.debug(dateString + " : WCA_RECEIVING_TIME = " + (lReadEndTime - lReadStartTime)); } myLog.logMsg(MyLog.DEBUG, "WCA_RECEIVING_TIME = " + (lReadEndTime - lReadStartTime)); nRcvLen = pDataBuff.length; myLog.logMsg(MyLog.INFO, "run] Receive Data Field Length = " + nRcvLen); // 5. 수신 데이타 처리 handleRcvData(nRcvLen, pDataBuff); } catch (java.lang.NumberFormatException n) { // 길이 데이타를 파싱못할경우... myLog.logMsg(MyLog.ERROR, "run] " + WCAException.displayError(WCAException.E_RECVERR_DATALEN, toString(), MyUtil.toHex(pLenBuff))); if (adapter_logger.isError()) { adapter_logger.error(WCAException.displayError(WCAException.E_RECVERR_DATALEN, toString(), MyUtil.toHex(pLenBuff))); } this.closeSoftLink(); } catch (SocketTimeoutException ste) { myLog.logMsg(MyLog.DEBUG, "run] SocketTimeoutException ocurrs"); nCheckOldWCAQueueCnt++; if (WCADefine.DEFAULT_SOCK_RCV_TIMEOUT * nCheckOldWCAQueueCnt > WCADefine.DEFAULT_TRANSACTION_DELETE_TIMEOUT) { myLog.logMsg(MyLog.DEBUG, "run] There is No Data to Read, Running..."); nCheckOldWCAQueueCnt = 0; myLog.logMsg(MyLog.DEBUG, "run] Check Old WCAQueue..."); /* long lCurrTime = System.currentTimeMillis(); // HashMap에 WCAQueue가 무한적 추가되는 것을 막기 위해서, 시간이 경과한 WCAQueue를 삭제함. synchronized(hmapRcvData) { Iterator iter = hmapRcvData.keySet().iterator(); while(iter.hasNext()) { String sKey = (String)iter.next(); if (sKey == null) { if (trc_logger.isDebug()) trc_logger.debug("run] sKey is null");} WCAQueue wcaQueue = (WCAQueue)hmapRcvData.get(sKey); if (wcaQueue == null) { if (trc_logger.isDebug()) trc_logger.debug("run] wcaQueue is null");} if (wcaQueue != null) { long lTimeGap = lCurrTime - wcaQueue.lCreateTime; if (lTimeGap > (WCADefine.DEFAULT_TRANSACTION_DELETE_TIMEOUT * 1000)) { myLog.logMsg(MyLog.ERROR, "run] Delete TRANSACTION Queue, Key = " + sKey); if (adapter_logger.isError()) adapter_logger.error(toString() + " Delete TRANSACTION Queue, Key = " + sKey); hmapRcvData.remove(sKey); } } } } */ } } catch (java.net.SocketException socket) { myLog.logMsg(MyLog.ERROR, "run] Error = " + socket.toString()); this.closeSoftLink(); } catch (Exception e) { myLog.logMsg(MyLog.ERROR, "run] Error = " + e.toString()); if (adapter_logger.isError()) { adapter_logger.error("[" + WCAException.E_ETC + "] " + toString() + " 프로그램 에러입니다. ", e); } this.closeSoftLink(); } } // 어댑터 상태 체크 setAdapterStatus(true); // 미처리 트랜잭션 출력 traceRemainTransaction(); // Thread 종료시 LOG 파일 close myLog.logMsg(MyLog.INFO, "run] " + toString() + " Thread is Stopped"); //adapter_logger.debug(toString() + " Thread is Stopped"); closeLogStream(); } /** * 1. 기능 : 수신 데이타 처리 * 2. 처리 개요 : * - 수신 데이타 트레이스 파일에 로깅 * - DATA TYPE에 따라 각 처리 함수로 분기한다. * 3. 주의사항 **/ public void handleRcvData(int nLen, byte[] pBuff) { String sDataType = null; boolean isLogFirstData = false; String strFirstData = ""; String luName = ""; String threadName = ""; long startTime = 0; WCAHeader wcaHeader = new WCAHeader(WCAHeader.WCA_HEADER_LEN, pBuff); nRcvCnt++; // 트레이스 로깅 /* synchronized(myTrc) { myTrc.logMsg("SoftLink -> WCA (LEN = " + nLen + ")"); myTrc.logMsg("WCA Header : " + wcaHeader.toString()); myTrc.logData(WCADefine.EBCDIC_CODE, nLen, pBuff); } */ sDataType = wcaHeader.getDataType(); myLog.logMsg(MyLog.INFO, "handleRcvData] Receive DATA_TYPE VALUE = " + sDataType ); // 송신 완료 if (sDataType.equals(WCAHeader.DATA_TYPE_SEND_OK)) { myLog.logMsg(MyLog.DEBUG, "handleRcvData] Status Mode : Send OK "); handleSendOK(nLen, pBuff); } else if (sDataType.equals(WCAHeader.DATA_TYPE_TIMEOUT_ONLY) || sDataType.equals(WCAHeader.DATA_TYPE_TIMEOUT_LAST)) { myLog.logMsg(MyLog.DEBUG, "handleRcvData] Status Mode : Timeout "); handleTimeout(nLen, pBuff); } else if (sDataType.equals(WCAHeader.DATA_TYPE_NORMAL_FIRST) || sDataType.equals(WCAHeader.DATA_TYPE_NORMAL_MIDDLE) || sDataType.equals(WCAHeader.DATA_TYPE_DFS_FIRST) || sDataType.equals(WCAHeader.DATA_TYPE_DFS_MIDDLE) || sDataType.equals(WCAHeader.DATA_TYPE_TIMEOUT_FIRST) || sDataType.equals(WCAHeader.DATA_TYPE_TIMEOUT_MIDDLE)) { myLog.logMsg(MyLog.DEBUG, "handleRcvData] Status Mode : Normal First, Normal Middle, Delay First, Delat Middel "); handleData(nLen, pBuff); } else if (sDataType.equals(WCAHeader.DATA_TYPE_NORMAL_ONLY) || sDataType.equals(WCAHeader.DATA_TYPE_NORMAL_LAST) || sDataType.equals(WCAHeader.DATA_TYPE_DFS_ONLY) || sDataType.equals(WCAHeader.DATA_TYPE_DFS_LAST)) { /// DEBUG_LOG : 20200406 isLogFirstData = false; // 운영 환경이 기본 로그 레벨이 warn임, 20200406 가용성 테스트 이후에 isInfo으로 변경 해야 함. (KB 김양규 차장님 요청 사항) if (adapter_logger.isInfo()) { // if (adapter_logger.isError()) { if (nLen > WCAHeader.WCA_HEADER_LEN + 60) { isLogFirstData = true; byte[] bFirstData = new byte[60]; System.arraycopy(pBuff, WCAHeader.WCA_HEADER_LEN, bFirstData, 0, 60); strFirstData = new String(CodeCvrt.cvrtEbc2Ksc(bFirstData)); luName = wcaHeader.getLUName(); threadName = Thread.currentThread().getName(); adapter_logger.error("handleRcvData> ST " + threadName + ", " + luName + ", " + strFirstData); startTime = System.currentTimeMillis(); } } myLog.logMsg(MyLog.DEBUG, "handleRcvData] Status Mode : NORML_ONLY, NORML_LAST, DFS"); handleNormalDFS(nLen, pBuff); if (isLogFirstData == true) { long endTime = System.currentTimeMillis(); long elapseTime = endTime - startTime; adapter_logger.error("handleRcvData> EN " + threadName + ", " + luName + ", " + strFirstData + ", " + elapseTime); if (elapseTime > 5000) { adapter_logger.error("handleRcvData> OVEROVERTIME " + elapseTime + ", " + threadName + ", " + luName + ", " + strFirstData); } else if (elapseTime > 1000) { adapter_logger.error("handleRcvData> OVERTIME " + elapseTime + ", " + threadName + ", " + luName + ", " + strFirstData); } } } else if (sDataType.equals(WCAHeader.DATA_TYPE_ERROR)) { myLog.logMsg(MyLog.DEBUG, "handleRcvData] Status Mode : Error"); handleError(nLen, pBuff); } else if (sDataType.equals(WCAHeader.DATA_TYPE_ADAPTER_ERROR) || sDataType.equals(WCAHeader.DATA_TYPE_ADAPTER_OK)) { myLog.logMsg(MyLog.DEBUG, "handleRcvData] Status Mode : DATA_TYPE_ADAPTER_ERROR, DATA_TYPE_ADAPTER_OK"); handleAutoBackup(nLen, pBuff); } else if (sDataType.equals(WCAHeader.DATA_TYPE_GET_ADAPTER_STATUS)) { myLog.logMsg(MyLog.DEBUG, "handleRcvData] Status Mode : DATA_TYPE_GET_ADAPTER_STATUS"); handleAutoBackup(nLen, pBuff); } else { myLog.logMsg(MyLog.ERROR, "handleRcvData] " + WCAException.displayError(WCAException.E_SOFTLINK_UNKNOWN_COMMAND, toString(), sDataType)); if (adapter_logger.isError()) { adapter_logger.error(WCAException.displayError(WCAException.E_SOFTLINK_UNKNOWN_COMMAND, toString(), sDataType)); } } return; } /** * 1. 기능 : 송신 완료 (Send OK) 데이타 처리 * 2. 처리 개요 : * - NONRESPONSE 모드 : * 1. 송신 Queue에 있을 경우 : 데이타 수신했음을 알려준다. * 2. 송신 Queue에 없을 경우 : 타임아웃 데이타로 INBOUND handleTimeoutData 핸들러로 보낸다. * - RESPONSE 모드 : 수신 데이타 대기한다. * 3. 주의사항 **/ public void handleSendOK(int nLen, byte[] pBuff) { myLog.logMsg(MyLog.DEBUG, "handleRcvData] Receive STATUS_SENDOK..."); String sKey = null; WCAHeader wcaHeader = new WCAHeader(WCAHeader.WCA_HEADER_LEN, pBuff); char cMode = wcaHeader.getMode(); myLog.logMsg(MyLog.DEBUG, "handleSendOK] Tran Mode = " + cMode); sKey = getKey(wcaHeader); myLog.logMsg(MyLog.DEBUG, "handleSendOK] Key = " + sKey); /* NONRESPONSE 모드 */ if (cMode == (WCAHeader.TRAN_MODE_NONRESPONSE).charAt(0)) { myLog.logMsg(MyLog.DEBUG, "handleSendOK] Response Mode = MODE_NONRESPONSE"); WCAQueue queueWSA = null; synchronized (hmapRcvData) { queueWSA = (WCAQueue)hmapRcvData.remove(sKey); } if (queueWSA != null) { synchronized (queueWSA) { queueWSA.setRecvSendOKFlag(true); WCAQueueData qdataWSA = new WCAQueueData(nLen, pBuff); myLog.logMsg(MyLog.DEBUG, "handleSendOK] Add Queue Data, Length = " + nLen); queueWSA.addDataToQueue(qdataWSA); myLog.logMsg(MyLog.DEBUG, "handleSendOK] Notify WLI Thread..."); queueWSA.notifyAll(); lNotifyEndTime = System.currentTimeMillis(); String dateString = formatter.format(ZonedDateTime.now()); if (adapter_logger.isDebug()) { adapter_logger.debug(dateString + " : WCA_PROCESSIING_TIME = " + (lNotifyEndTime - lReadEndTime)); } } } else { if (wcaEventHandler != null) { myLog.logMsg(MyLog.DEBUG, "handleSendOK] Call Event Handler : handleTimeoutData()"); wcaEventHandler.handleTimeoutData(sAdapterGroupName, sAdapterName, sGroupCode, nLen, pBuff); } else { myLog.logMsg(MyLog.ERROR, "handleSendOK] Event Handler is Not Registered, So Discard Data..."); } } } else if (cMode == (WCAHeader.TRAN_MODE_RESPONSE).charAt(0) || cMode == (WCAHeader.TRAN_MODE_TERMINAL).charAt(0)) { myLog.logMsg(MyLog.DEBUG, "handleSendOK] Response Mode = MODE_RESPONSE"); myLog.logMsg(MyLog.DEBUG, "handleSendOK] Wait Host Data..."); WCAQueue queueWSA = null; synchronized (hmapRcvData){ queueWSA = (WCAQueue)hmapRcvData.get(sKey); if (queueWSA != null) queueWSA.setRecvSendOKFlag(true); } } else { myLog.logMsg(MyLog.ERROR, "handleSendOK] Receive Unknown Mode, Mode = " + cMode); } return; } /** * 1. 기능 : Timeout 데이타 처리 * 2. 처리 개요 : * - TIMOUT 첫번째 데이타일 경우 (DATA_TYPE_TIMEOUT_ONLY) : * 수신데이타를 INBOUND 핸들러로 보낸다. * - TIMOUT 데이타가 하나이상의 패킷일 경우 : * Queue에 저장된 키값을 구한다. (key값이 없을 경우 에러로그만 남긴다.) * 1. 송신 Queue에 있을 경우 : 수신된 모든 데이타를 INBOUND 핸들러로 보낸다. * 2. 송신 Queue에 없을 경우 : 현재 받은 데이타만 INBOUND 핸들러로 보낸다. * 3. 주의사항 **/ public void handleTimeout(int nLen, byte[] pBuff) { String sKey = null; String sDataType = null; byte[] pRecvBuff = null; char cMode; WCAHeader wcaHeader = new WCAHeader(WCAHeader.WCA_HEADER_LEN, pBuff); sDataType = wcaHeader.getDataType(); myLog.logMsg(MyLog.DEBUG, "handleTimeout] Data Type = " + sDataType); cMode = wcaHeader.getMode(); myLog.logMsg(MyLog.DEBUG, "handleTimeout] Tran Mode = " + cMode); if (sDataType.equals(WCAHeader.DATA_TYPE_TIMEOUT_ONLY)){ pRecvBuff = pBuff; } else { sKey = getKey(wcaHeader); if (sKey == null) { myLog.logMsg(MyLog.ERROR, "handleTimeout] Key is NULL" ); if (adapter_logger.isError()) { adapter_logger.error("handleTimeout] - " + WCAException.displayError(WCAException.E_RECVDATA_ERROR, toString(), "Key is NULL")); } return; } WCAQueue queueWSA = null; synchronized (hmapRcvData) { queueWSA = (WCAQueue)hmapRcvData.remove(sKey); } if (queueWSA != null) { synchronized (queueWSA) { WCAQueueData qdataWSA = new WCAQueueData(nLen, pBuff); myLog.logMsg(MyLog.DEBUG,"handleTimeout] Add Queue Data, Length = " + nLen); queueWSA.addDataToQueue(qdataWSA); } pRecvBuff = queueWSA.getDataFromQueue(); } else { myLog.logMsg(MyLog.ERROR, "handleTimeout] - [" + WCAException.E_SOFTLINK_RECV_DATA_NOTFOUND + "] Queue Data doesn't existed...."); if (adapter_logger.isError()) { adapter_logger.error("handleTimeout] - [" + WCAException.E_SOFTLINK_RECV_DATA_NOTFOUND + "] " + toString() + " Queue Data doesn't existed...."); } return; } } if (wcaEventHandler != null) { myLog.logMsg(MyLog.DEBUG, "handleTimeout] Call Event Handler : handleTimeoutData()"); wcaEventHandler.handleTimeoutData(sAdapterGroupName, sAdapterName, sGroupCode, pRecvBuff.length, pRecvBuff); } else { myLog.logMsg(MyLog.ERROR, "handleTimeout] Event Handler is Not Registered, So Discard Data..."); } } /** * 1. 기능 : 수신 데이타를 Queue에 저장한다. * 2. 처리 개요 : * - DATA TYPE이 FIRST, MIDDEL인 경우 Queue에 저장될 key 값을 구하여 Queue 값을 구한다. * - Queue에 수신데이타 저장 값이 있을 경우 Queue 데이타를 추가하며, * 없을 경우 Queue를 생성하여 Queue 데이타를 추가한다. * - Respnse 모드이고 timeout 데이타인 경우 setResTimeoutFlag(true)을 설정해준다. * (차후 INBOUND 핸들러로 보내기 위함) * 3. 주의사항 * **/ public void handleData(int nLen, byte[] pBuff) { String sKey = null; WCAHeader wcaHeader = new WCAHeader(WCAHeader.WCA_HEADER_LEN, pBuff); sKey = getKey(wcaHeader); if (sKey == null) { myLog.logMsg(MyLog.ERROR, "handleData] - "+ WCAException.displayError(WCAException.E_RECVDATA_ERROR, toString(), "Key is NULL")); if (adapter_logger.isError()) { adapter_logger.error("handleData] - "+ WCAException.displayError(WCAException.E_RECVDATA_ERROR, toString(), "Key is NULL")); } return; } WCAQueue queueWSA = null; synchronized (hmapRcvData) { queueWSA = (WCAQueue)hmapRcvData.get(sKey); } // Status가 DATA_TYPE_TIMEOUT_FIRST인 경우 LUNAME으로 Hashmap에 저장한다. String sDataType = wcaHeader.getDataType(); char cMode = wcaHeader.getMode(); myLog.logMsg(MyLog.DEBUG, "handleData] Data Type = " + sDataType + ", Mode = " + cMode); if (queueWSA == null) { queueWSA = new WCAQueue(); registerRcvQueue(sKey, queueWSA); // DFS가 아니고 response 모드인 경우 -> 타임아웃데이타 if ((String.valueOf(cMode).equals(WCAHeader.TRAN_MODE_RESPONSE) || String.valueOf(cMode).equals(WCAHeader.TRAN_MODE_TERMINAL)) && !sDataType.substring(0,1).equals(WCAHeader.DATA_TYPE_DFS_PREFIX)) { queueWSA.setResTimeoutFlag(true); } } if (queueWSA != null) { synchronized (queueWSA) { WCAQueueData qdataWSA = new WCAQueueData(nLen, pBuff); myLog.logMsg(MyLog.DEBUG,"handleData] Add Queue Data, Length = " + nLen); queueWSA.addDataToQueue(qdataWSA); } } return; } /** * 1. 기능 : Normal Data 및 DFS 데이타를 처리한다. * 2. 처리 개요 : * - NONRESPONSE 모드 : * 1. Queue에 있을 경우 : 수신된 모든 데이타를 INBOUND 핸들러로 보낸다. * 2. Queue에 없을 경우 : 수신된 현재 데이타를 INBOUND 핸들러로 보낸다. * - RESPONSE 모드 : * 1. Queue에 있을 경우 : RESPONSE 모드이고 TIMEOUT 데이타이면 INBOUND 핸들러로 보낸다. * 그외의 경우 데이타 수신했음을 알려준다. (notify) * 2. Queue에 없을 경우 : timeout 데이타로 INBOUND 핸들러로 보낸다. * 3. 주의사항 * **/ public void handleNormalDFS(int nLen, byte[] pBuff) { String sKey = null; char cMode; byte[] pRecvBuff = null; WCAHeader wcaHeader = new WCAHeader(WCAHeader.WCA_HEADER_LEN, pBuff); sKey = getKey(wcaHeader); if (sKey == null) { myLog.logMsg(MyLog.ERROR, "handleNormalDFS] - " + WCAException.displayError(WCAException.E_RECVDATA_ERROR, toString(), "Key is NULL")); if (adapter_logger.isError()) { adapter_logger.error("handleNormalDFS] - " + WCAException.displayError(WCAException.E_RECVDATA_ERROR, toString(), "Key is NULL")); } return; } cMode = wcaHeader.getMode(); myLog.logMsg(MyLog.DEBUG, "handleNormalDFS] Tran Mode = " + cMode); if (cMode == (WCAHeader.TRAN_MODE_NONRESPONSE).charAt(0)) { WCAQueue queueWSA = null; synchronized(hmapRcvData) { queueWSA = (WCAQueue)hmapRcvData.remove(sKey); } if (queueWSA != null) { synchronized (queueWSA) { WCAQueueData qdataWSA = new WCAQueueData(nLen, pBuff); myLog.logMsg(MyLog.DEBUG,"handleNormalDFS] Add Queue Data, Length = " + nLen); queueWSA.addDataToQueue(qdataWSA); } pRecvBuff = queueWSA.getDataFromQueue(); } else { pRecvBuff = pBuff; myLog.logMsg(MyLog.DEBUG, "handleNormalDFS] - [" + WCAException.E_SOFTLINK_RECV_DATA_NOTFOUND +"] Queue Data doesn't existed...."); } if (wcaEventHandler != null) { myLog.logMsg(MyLog.DEBUG, "handleNormalDFS] Call Event Handler : handleNonRspData()"); wcaEventHandler.handleNonRspData(sAdapterGroupName, sAdapterName, sGroupCode, pRecvBuff.length, pRecvBuff); } else { myLog.logMsg(MyLog.ERROR, "handleNormalDFS] Event Handler is Not Registered, So Discard Data..."); } } else if (cMode == (WCAHeader.TRAN_MODE_RESPONSE).charAt(0) || cMode == (WCAHeader.TRAN_MODE_TERMINAL).charAt(0)) { WCAQueue queueWSA = null; synchronized (hmapRcvData) { queueWSA = (WCAQueue)hmapRcvData.remove(sKey); } if (queueWSA != null) { synchronized (queueWSA) { WCAQueueData qdataWSA = new WCAQueueData(nLen, pBuff); myLog.logMsg(MyLog.DEBUG,"handleNormalDFS] Add Queue Data, Length = " + nLen); queueWSA.addDataToQueue(qdataWSA); // timeout데이타일 경우 if (queueWSA.getResTimeoutFlag()) { pRecvBuff = queueWSA.getDataFromQueue(); if (wcaEventHandler != null) { myLog.logMsg(MyLog.DEBUG, "handleNormalDFS] Call Event Handler : handleTimeoutData()"); wcaEventHandler.handleTimeoutData(sAdapterGroupName, sAdapterName, sGroupCode, pRecvBuff.length, pRecvBuff); } else { myLog.logMsg(MyLog.ERROR, "handleNormalDFS] Event Handler is Not Registered, So Discard Data..."); } } else { myLog.logMsg(MyLog.DEBUG, "handleNormalDFS] Notify WLI Thread..."); // 20200724 Start if (adapter_logger.isInfo()) { adapter_logger.debug("Before Notify WLI Thread, " + sAdapterGroupName + ", " + sAdapterName + ", " + sGroupCode); } // 20200724 End queueWSA.notifyAll(); // 20200724 Start if (adapter_logger.isInfo()) { adapter_logger.debug("After Notify WLI Thread, " + sAdapterGroupName + ", " + sAdapterName + ", " + sGroupCode); } // 20200724 End lNotifyEndTime = System.currentTimeMillis(); String dateString = formatter.format(ZonedDateTime.now()); // 20200724 Start // 로그 레벨 변경 // if (adapter_logger.isDebug()) { adapter_logger.debug(dateString + " : WCA_PROCESSIING_TIME = " + (lNotifyEndTime - lReadEndTime)); } if (adapter_logger.isInfo()) { adapter_logger.info(dateString + " : WCA_PROCESSIING_TIME = " + (lNotifyEndTime - lReadEndTime)); } // 20200724 End } } } else { if (wcaEventHandler != null) { myLog.logMsg(MyLog.DEBUG, "handleNormalDFS] Call Event Handler : handleTimeoutData()"); wcaEventHandler.handleTimeoutData(sAdapterGroupName, sAdapterName, sGroupCode, nLen, pBuff); } else { myLog.logMsg(MyLog.ERROR, "handleNormalDFS] Event Handler is Not Registered, So Discard Data..."); } } } else { myLog.logMsg(MyLog.ERROR, "handleNormalDFS] Receive Unknown Mode, Mode = " + cMode); adapter_logger.error("handleNormalDFS] - " + WCAException.displayError(WCAException.E_SOFTLINK_UNKNOWN_COMMAND, toString(), "Unknown Mode = " + cMode) ); } } /** * 1. 기능 : ERROR Data 및 DFS 데이타를 처리한다. * 2. 처리 개요 : * - Queue에 있을 경우 : * 1. "LU사용중"이라는 에러코드인 경우 setResendFlag(true)로 설정한다. * (차후 다른 LU 그룹으로 Resend 하기 위함) * 2. 그외의 경우 : 그외의 경우 데이타 수신했음을 알려준다. (notify) * - Queue에 없을 경우 : 수신된 데이타를 INBOUND 핸들러로 보낸다. * 3. 주의사항 * **/ public void handleError(int nLen, byte[] pBuff) { String sKey = null; byte[] bErrCode = new byte[WCAException.SOFTLINK_ERROR_SIZE]; byte[] bErrMsg = null; WCAHeader wcaHeader = new WCAHeader(WCAHeader.WCA_HEADER_LEN, pBuff); if (nLen >= (WCAHeader.WCA_HEADER_LEN + WCAException.SOFTLINK_ERROR_SIZE)) { System.arraycopy(pBuff, WCAHeader.WCA_HEADER_LEN, bErrCode, 0, WCAException.SOFTLINK_ERROR_SIZE); String sErrCode = new String(bErrCode); myLog.logMsg(MyLog.DEBUG, "handleError] ErrCode = " + sErrCode); } if (nLen > (WCAHeader.WCA_HEADER_LEN + WCAException.SOFTLINK_ERROR_SIZE)) { bErrMsg = new byte[nLen - WCAHeader.WCA_HEADER_LEN - WCAException.SOFTLINK_ERROR_SIZE]; System.arraycopy(pBuff, WCAHeader.WCA_HEADER_LEN + WCAException.SOFTLINK_ERROR_SIZE, bErrMsg, 0, nLen - WCAHeader.WCA_HEADER_LEN - WCAException.SOFTLINK_ERROR_SIZE); String sErrMsg = new String(bErrMsg); myLog.logMsg(MyLog.DEBUG, "handleError] ErrMsg = " + sErrMsg); } sKey = getKey(wcaHeader); myLog.logMsg(MyLog.DEBUG, "handleError] Key = " + sKey); if (bErrCode != null && bErrMsg != null) { String sRecvErrCode = new String(bErrCode); if (adapter_logger.isError()) { adapter_logger.error("[" + sRecvErrCode+"] " + toString() + " " + sKey + " : " + new String(bErrMsg)); } } WCAQueue queueWSA = null; synchronized (hmapRcvData) { queueWSA = (WCAQueue)hmapRcvData.remove(sKey); } if (queueWSA != null) { // 해당 LU 세션이 사용중, 다운일 경우 다른 LU 세션으로 보낸다. if (new String(bErrCode).equals(WCAException.E_HOST_LU_DOWN) || new String(bErrCode).equals(WCAException.E_HOST_LU_IN_USED) || new String(bErrCode).equals(WCAException.E_HOST_LU_NON_EXIST)) { queueWSA.setResendFlag(true); } synchronized (queueWSA) { WCAQueueData qdataWSA = new WCAQueueData(nLen, pBuff); myLog.logMsg(MyLog.DEBUG,"handleError] Add Queue Data, Length = " + nLen); queueWSA.addDataToQueue(qdataWSA); myLog.logMsg(MyLog.DEBUG, "handleError] Notify WLI Thread..."); queueWSA.notifyAll(); lNotifyEndTime = System.currentTimeMillis(); String dateString = formatter.format(ZonedDateTime.now()); if (adapter_logger.isDebug()) adapter_logger.debug(dateString + " : WCA_PROCESSIING_TIME = " + (lNotifyEndTime - lReadEndTime)); } } else { /* if (wcaEventHandler != null) { myLog.logMsg(MyLog.DEBUG, "handleError] Call Event Handler : handleTimeoutData()"); wcaEventHandler.handleTimeoutData(sAdapterGroupName, sAdapterName, nLen, pBuff); } else { myLog.logMsg(MyLog.ERROR, "handleError] Event Handler is Not Registered, So Discard Data..."); } */ myLog.logMsg(MyLog.DEBUG, "handleError] Doesnt' Exist Data in Queue!!"); } } /** * 1. 기능 : 수동 백업 및 복구 명령을 처리한다. * 2. 처리 개요 : * - DATA_TYPE_ADAPTER_ERROR 인 경우 : 해당 어댑터 그룹, LU 그룹을 백업모드로 전환한다. * - DATA_TYPE_ADAPTER_OK 인 경우 : 해당 어댑터 그룹, LU 그룹을 백업모드에서 복귀한다. * 3. 주의사항 * **/ public void handleAutoBackup(int nLen, byte[] pBuff) { ManualBackupCmd cmd = new ManualBackupCmd(ManualBackupCmd.BACKUP_CMD_LEN, pBuff); String sBackupAdapterGrpName = null; String sBackupLUGrpName = null; try { String sDataType = cmd.getDataType(); sBackupAdapterGrpName = cmd.getAdapterGrpName(); sBackupLUGrpName = cmd.getLUGrpName(); // 20090810 Start if (bBackupEnableFlag == false) { myLog.logMsg(MyLog.NOTICE, "handleAutoBackup] Backup Enable Flag is False, So Ignore 자동 백업 명령 (" + sBackupAdapterGrpName + "/" + sNodeName + "/" + sBackupLUGrpName + ")"); return; } // 20090810 End // 수동 백업 전환 if (sDataType.equals(ManualBackupCmd.DATA_TYPE_ADAPTER_ERROR)) { myLog.logMsg(MyLog.NOTICE, "handleAutoBackup] 자동 백업 명령 수신 (" + sBackupAdapterGrpName + "/" + sNodeName + "/" + sBackupLUGrpName + ")"); adapter_logger.warn("handleAutoBackup] - " + toString() + " 자동 백업 명령 수신 " + sBackupAdapterGrpName + "/" + sBackupLUGrpName); if (bBackupEnableFlag == true) { if (isBackupSessionPool()) { return; } snaAdapter.setAutoBackupMode(sNodeName, sBackupLUGrpName, true); } else { myLog.logMsg(MyLog.NOTICE, "handleAutoBackup] bBackupEnableFlag is False, So Ignore Data"); adapter_logger.warn("handleAutoBackup] bBackupEnableFlag is False, So Ignore Data"); } // 20090810 End } else { // 수동 복구 전환 myLog.logMsg(MyLog.NOTICE, "handleAutoBackup] 자동 복구 명령 수신 (" + sBackupAdapterGrpName + "/" + sBackupLUGrpName + ")"); adapter_logger.warn("handleAutoBackup] - " + toString() + " 자동 복구 명령 수신 " + sBackupAdapterGrpName + "/" + sBackupLUGrpName); if (bBackupEnableFlag == true) { if (isBackupSessionPool()) { return; } snaAdapter.setAutoBackupMode(sNodeName, sBackupLUGrpName, false); } else { myLog.logMsg(MyLog.NOTICE, "handleAutoBackup] bBackupEnableFlag is False, So Ignore Data"); adapter_logger.warn("handleAutoBackup] bBackupEnableFlag is False, So Ignore Data"); } // 20090810 End } } catch (WCAException e) { // 해당 세션을 찾지 못하였을 경우 if (e.getErrorReturnCode().equals(WCAException.E_SOFTLINK_NOT_FOUND_SESSION)) { adapter_logger.error(WCAException.displayError(WCAException.E_SOFTLINK_NOT_FOUND_SESSION, "백업 전환/복구 세션 시 발생[" + sBackupAdapterGrpName + "/" + sBackupLUGrpName + "]")); } } } /** * 1. 기능 : Header 데이타에서 Queue에 저장된 Key 값 추출 * 2. 처리 개요 : * - Transaction Key가 없는경우 LU 이름으로 한다. * 3. 주의사항 * **/ private String getKey(WCAHeader wcaHeader) { String sKey = wcaHeader.getKey(); if (sKey == null || (sKey != null && sKey.equals(new String(WCAHeader.NULL_TRANKEY)))) { myLog.logMsg(MyLog.DEBUG, "getKey] Key is null or empty, So LuName is Key " ); sKey = wcaHeader.getLUName().trim(); } myLog.logMsg(MyLog.DEBUG, "getKey] Key = (" + sKey + ")"); if (sKey == null || (sKey != null && sKey.equals(new String(WCAHeader.NULL_TSNAME)))) { myLog.logMsg(MyLog.DEBUG, "getKey] Key, LuName is null or empty" ); return null; } return sKey; } /** * 1. 기능 : SoftLink 세션을 통해서 데이터를 수신한다. * 2. 처리 개요 : * - SoftLink 세션을 통해서 파라미터인 nDataLen 값 만큼 데이터를 수신한다. * - 정해진 데이터를 nTimeout시간안에 수신하지 못하면 장애처리 한다. * 3. 주의사항 * - 이 함수를 호출하기 전에 먼저 데이터 길이 필드를 수신한 해야 한다. * * @param nTimeout 데이터 수신 Timeout * @param nDataLen 수신할 데이터 길이 * @return pBuff 수신된 데이터가 저장된 버퍼 */ public byte[] recvDataField(int nTimeout, int nDataLen) { byte[] pBuff = null; int nRcvLen = 0; int nRemainLen = 0; int nBuffPos = 0; long lStartTime = 0; long lCurrTime = 0; try { pBuff = new byte[nDataLen]; nRemainLen = nDataLen; //sockSoftLink.setSoTimeout(1000); sockSoftLink.setSoTimeout(0); lStartTime = new Date().getTime(); myLog.logMsg(MyLog.DEBUG, "[Before Receiving Data] "); while (nRemainLen > 0) { nRcvLen = isSoftLink.read(pBuff, nBuffPos, nRemainLen); if (nRcvLen < 0) { myLog.logMsg(MyLog.ERROR, "recvDataField] " + WCAException.displayError(WCAException.E_SOFTLINK_NOTCONN, toString()) + " ( nRcvLen = " + nRcvLen + ")"); if (adapter_logger.isError()) { adapter_logger.error(WCAException.displayError(WCAException.E_SOFTLINK_NOTCONN, toString())); } return null; } else { nRemainLen -= nRcvLen; nBuffPos += nRcvLen; } lCurrTime = new Date().getTime(); if (lCurrTime - lStartTime > (nTimeout * 1000)) { sockSoftLink.setSoTimeout(0); if (adapter_logger.isError()) { adapter_logger.error("recvDataField] - " + toString() + " Recv Timeout, StartTime = " + lStartTime + ", CurrTime = " + lCurrTime); } myLog.logMsg(MyLog.ERROR, "recvDataField] Recv Timeout, StartTime = " + lStartTime + ", CurrTime = " + lCurrTime); return null; } } myLog.logMsg(MyLog.DEBUG, "[After Receiving Data] "); sockSoftLink.setSoTimeout(0); return pBuff; } catch(Exception e) { myLog.logMsg(MyLog.ERROR, "recvDataField] Error :" + e.toString()); if (adapter_logger.isError()) { adapter_logger.error("recvDataField] " + WCAException.E_ETC + "] " + toString() + " Error :" + e.toString()); } try { sockSoftLink.setSoTimeout(0); } catch(SocketException se) { myLog.logMsg(MyLog.ERROR, "recvDataField] Error :" + e.toString()); if (adapter_logger.isError()) { adapter_logger.error("recvDataField] - [" + WCAException.E_ETC + "] " + toString() + " Error :" + e.toString()); } } return null; } } public byte[] recvLenthField(int nDataLen) throws Exception { byte[] pBuff = null; int nRcvLen = 0; int nRemainLen = 0; int nBuffPos = 0; try { pBuff = new byte[nDataLen]; nRemainLen = nDataLen; //sockSoftLink.setSoTimeout(1000 * WCADefine.DEFAULT_SOCK_RCV_TIMEOUT); sockSoftLink.setSoTimeout(0); myLog.logMsg(MyLog.DEBUG, "[Before Receiving Data Length] "); while (nRemainLen > 0) { nRcvLen = isSoftLink.read(pBuff, nBuffPos, nRemainLen); if (nRcvLen < 0) { myLog.logMsg(MyLog.ERROR, "recvLenthField] " + WCAException.displayError(WCAException.E_SOFTLINK_NOTCONN, toString()) + " ( nRcvLen = " + nRcvLen + ")"); if (adapter_logger.isError()) { adapter_logger.error(WCAException.displayError(WCAException.E_SOFTLINK_NOTCONN, toString())); } return null; } else { nRemainLen -= nRcvLen; nBuffPos += nRcvLen; } } myLog.logMsg(MyLog.DEBUG, "[After Receiving Data Length] "); sockSoftLink.setSoTimeout(0); return pBuff; } catch (Exception e) { throw e; } } /** * 1. 기능 : SoftLink TCP 세션 상태 설정 * 2. 처리 개요 : * 3. 주의사항 * * @param 세션 상태 * 0 : 연결안됨, 1 : TCP 세션 연결, 2 : TCP 세션 사용중 (사용안함) */ public void setSessionStat(int nSessStat) { this.nSessStat = nSessStat; } /** * 1. 기능 : SoftLink TCP 세션 이용 가능 상태 반환 * 2. 처리 개요 : * - SESS_STAT_READY 일 경우 true 반환 * 3. 주의사항 * * @param 세션 상태 * 0 : 연결안됨 (SESS_STAT_NOTCONN), * 1 : TCP 세션 연결 (SESS_STAT_READY), * 2 : TCP 세션 사용중 (SESS_STAT_INUSE - 사용안함) */ public boolean isAvailable() { boolean bAvailable = false; if (nSessStat == WCADefine.SESS_STAT_READY) { bAvailable = true; } else { bAvailable = false; } return bAvailable; } /** * 1. 기능 : Softlink와 연결된 세션수를 반환 * 2. 처리 개요 : * 3. 주의사항 * * @return Softlink와 연결된 세션수 **/ public int getConnectedSessNum() { int nSessNum = 0; if (nSessStat > 0) { nSessNum++; } return nSessNum; } /** * 1. 기능 : 호스트로 송신한 데이터를 SoftLink 세션을 통해서 호트로 송신한다. * 2. 처리 개요 : * - 트레이스 파일에 해당 데이터를 트레이스한다. * - 데이터의 내용을 호스트로 송신하기 위해 SoftLink 세션으로 송신한다. * 3. 주의사항 * - 트레이스 처리의 동기화를 위해서 myTrc 클래스에 대한 동기화를 수행한다. * - 송신 데이터 버퍼 형식 : 길이(4) + Data(n) * * @param nLen 송신할 데이터의 길이 * @param pBuff 송신할 데이터가 저장된 버퍼 * @return nLen 송신된 데이터 길이 * @exception WCAException */ public int sendData(int nLen, byte[] pBuff) throws WCAException { byte[] pLenBuff = null; long lStartTime = 0L, lEndTime = 0L; WCAHeader wcaHeader = null; try { // 길이에 대한 길이 필드 생성 // 20090302 Start // pLenBuff = MyUtil.getLenBuff(nLen, WCADefine.LEGTH_FIELD_SIZE); pLenBuff = setInt(nLen); // 20090302 End wcaHeader = new WCAHeader(WCAHeader.WCA_HEADER_LEN, pBuff); // 데이터 트레이스 /* synchronized(myTrc) { myTrc.logMsg("WCA -> SoftLink (LEN = " + nLen + ")"); myTrc.logMsg("WCA Header : " + wcaHeader.toString()); myTrc.logData(WCADefine.EBCDIC_CODE, nLen, pBuff); } */ // 길이 필드 및 데이터 송신 synchronized (osSoftLink) { String dateString = formatter.format(ZonedDateTime.now()); lStartTime = System.currentTimeMillis(); osSoftLink.write(pLenBuff, 0, WCADefine.LEGTH_FIELD_SIZE); osSoftLink.write(pBuff, 0, nLen); osSoftLink.flush(); lEndTime = System.currentTimeMillis(); if (adapter_logger.isDebug()) { adapter_logger.debug(dateString + " : WCA_SENDING_TIME = " + (lEndTime - lStartTime) + ", KEY = "+wcaHeader.getKey()); } } /* synchronized(myTrc) { myTrc.logMsg("[After Sending] WCA_SENDING_TIME = " + (lEndTime - lStartTime) + "("+wcaHeader.getKey() + ")"); myTrc.logMsg("[After Sending] WCA -> SoftLink : " + wcaHeader.toString()); } */ nSndCnt++; return nLen; } catch (IOException ioe) { adapter_logger.error(WCAException.E_SOFTLINK_SENDERR, ioe); throw new WCAException(WCAException.E_SOFTLINK_SENDERR, ioe); } catch (Exception e) { adapter_logger.error(WCAException.E_SOFTLINK_SENDERR, e); throw new WCAException(WCAException.E_SOFTLINK_SENDERR, e); } } // 20090810 Start /** * 1. 기능 : WCA 어댑터 APP_CODE 명령 전송 * 2. 처리 개요 : * 3. 주의사항 * * @exception WCAException */ public void sendWcaSessionAppCode(boolean bSendAdapterInfo) throws WCAException { int nLen = 0; byte[] pBuff = null; byte[] pLenBuff = null; String sAppCode = ""; // String sSendWcaAdapterInfo = "0"; StringBuffer sbAppCode = new StringBuffer(); // 20190828 Start try { /* sSendWcaAdapterInfo = AdapterPropManager.getInstance().getProperty(sAdapterName, "SEND_WCA_ADAPTER_INFO"); if ("1".compareToIgnoreCase(sSendWcaAdapterInfo) == 0) { this.sendWcaAdapterInfo(); } */ if (bSendAdapterInfo == true) { this.sendWcaAdapterInfo(); } } catch (Exception e) { adapter_logger.error(WCAException.E_SOFTLINK_SENDERR, e); } // 20190828 End try { // 어댑터 프라퍼티에 등록할 경우 sAppCode = AdapterPropManager.getInstance().getProperty(sAdapterName, "APP_CODE"); // For Test // sDataCode = "ABC,DEF,XYZ"; // APP_CODE 값이 NULL 이거나 길이가 0이라도 Softlink APP 코드 정보를 클리어 하기 위해 보내야 함. if (sAppCode == null) { myLog.logMsg(MyLog.WARN, "sendWcaSessionAppCode> Data Code is null, So Send Dummy App Code to Softlink"); sAppCode = ""; sbAppCode.append(sAppCode); } else { sAppCode = sAppCode.trim(); if (sAppCode.length() < 3) { myLog.logMsg(MyLog.WARN, "sendWcaSessionAppCode> Data Code[" + sAppCode + "] is Invalid, So Send Dummy App Code to Softlink"); sAppCode = ""; sbAppCode.append(sAppCode); } else { // 불필요한 공백 삭제 ArrayList alDataCode = MyUtil.stringTokenizer(sAppCode, ","); if (alDataCode != null) { for (int i = 0; i < alDataCode.size(); i++) { String sTempDataCode = (String)alDataCode.get(i); sbAppCode.append(sTempDataCode.trim()); // 마지막 항목이 아니면 "," 추가 if (i != (alDataCode.size() - 1)) { sbAppCode.append(","); } } } } } AppCodeCmd cmd = new AppCodeCmd(sbAppCode.toString()); pBuff = cmd.getData(); nLen = pBuff.length; // 길이에 대한 길이 필드 생성 // 20090302 Start // pLenBuff = MyUtil.getLenBuff(nLen, WCADefine.LEGTH_FIELD_SIZE); pLenBuff = setInt(nLen); // 20090302 End myLog.logMsg(MyLog.WARN, "sendWcaSessionDataCode> App Code = " + sbAppCode.toString()); myLog.logData(WCADefine.ASCII_CODE, nLen, pBuff); // 길이 필드 및 데이터 송신 synchronized (osSoftLink) { osSoftLink.write(pLenBuff, 0, WCADefine.LEGTH_FIELD_SIZE); osSoftLink.write(pBuff, 0, nLen); osSoftLink.flush(); } } catch (IOException ioe) { adapter_logger.error(WCAException.E_SOFTLINK_SENDERR, ioe); throw new WCAException(WCAException.E_SOFTLINK_SENDERR, ioe); } catch (Exception e) { adapter_logger.error(WCAException.E_SOFTLINK_SENDERR, e); throw new WCAException(WCAException.E_SOFTLINK_SENDERR, e); } } // 20090810 End // 20190828 Start /** * 1. 기능 : 어댑터 정보 명령 전송 * 2. 처리 개요 : * 3. 주의사항 * * @exception WCAException */ public void sendWcaAdapterInfo() throws WCAException { int nLen = 0; byte[] pBuff = null; byte[] pLenBuff = null; String sAdptInfo = ""; try { sAdptInfo = this.sAdapterName; WCAAdapterInfoCmd cmd = new WCAAdapterInfoCmd(sAdptInfo); pBuff = cmd.getData(); nLen = pBuff.length; // 길이에 대한 길이 필드 생성 // 20090302 Start // pLenBuff = MyUtil.getLenBuff(nLen, WCADefine.LEGTH_FIELD_SIZE); pLenBuff = setInt(nLen); // 20090302 End myLog.logMsg(MyLog.WARN, "sendWcaAdapterInfo> Adapter Info = " + sAdptInfo); myLog.logData(WCADefine.ASCII_CODE, nLen, pBuff); // 길이 필드 및 데이터 송신 synchronized (osSoftLink) { osSoftLink.write(pLenBuff, 0, WCADefine.LEGTH_FIELD_SIZE); osSoftLink.write(pBuff, 0, nLen); osSoftLink.flush(); } } catch (IOException ioe) { adapter_logger.error(WCAException.E_SOFTLINK_SENDERR, ioe); throw new WCAException(WCAException.E_SOFTLINK_SENDERR, ioe); } catch (Exception e) { adapter_logger.error(WCAException.E_SOFTLINK_SENDERR, e); throw new WCAException(WCAException.E_SOFTLINK_SENDERR, e); } } // 20190828 End /** * 1. 기능 : 어댑터 상태 명령 전송 * 2. 처리 개요 : * 3. 주의사항 * * @exception WCAException */ public void sendAdapterStatusData() throws WCAException { int nLen = 0; byte[] pBuff = null; byte[] pLenBuff = null; try { // 첫번째 세션만 수행 if (nSessId != 0) { return; } if (this.isBackupSessionPool()) { return; } ManualBackupCmd cmd = new ManualBackupCmd(); cmd.setAdapterGrpName(this.sAdapterGroupName); cmd.setLUGrpName(this.sGroupCode); cmd.setDataType(WCAHeader.DATA_TYPE_GET_ADAPTER_STATUS); pBuff = cmd.getData(); nLen = pBuff.length; // 길이에 대한 길이 필드 생성 // 20090302 Start // pLenBuff = MyUtil.getLenBuff(nLen, WCADefine.LEGTH_FIELD_SIZE); pLenBuff = setInt(nLen); // 20090302 End // 데이터 트레이스 /* WCAHeader wcaHeader = new WCAHeader(WCAHeader.WCA_HEADER_LEN, pBuff); synchronized(myTrc) { myTrc.logMsg("WCA -> SoftLink (LEN = " + nLen + ")"); myTrc.logMsg("WCA Header : " + wcaHeader.toString()); myTrc.logData(WCADefine.EBCDIC_CODE, nLen, pBuff); } */ // 길이 필드 및 데이터 송신 synchronized (osSoftLink) { osSoftLink.write(pLenBuff, 0, WCADefine.LEGTH_FIELD_SIZE); osSoftLink.write(pBuff, 0, nLen); osSoftLink.flush(); } } catch (IOException ioe) { adapter_logger.error(WCAException.E_SOFTLINK_SENDERR, ioe); throw new WCAException(WCAException.E_SOFTLINK_SENDERR, ioe); } catch (Exception e) { adapter_logger.error(WCAException.E_SOFTLINK_SENDERR, e); throw new WCAException(WCAException.E_SOFTLINK_SENDERR, e); } } /** * 1. 기능 : Softlink TCP 세션 close * 2. 처리 개요 : * 3. 주의사항 **/ public void closeSoftLink() { try { try { if (nSessStat != WCADefine.SESS_STAT_NOTCONN) { // 20200825 Start if (isSoftLink != null) { try { isSoftLink.close(); isSoftLink = null; } catch (Exception ignore1) { adapter_logger.error("closeSoftLink] - [" + WCAException.E_ETC +"] " + toString() + " isSoftLink.close, Error = " + ignore1.toString()); } } if (osSoftLink != null) { try { osSoftLink.close(); osSoftLink = null; } catch (Exception ignore2) { adapter_logger.error("closeSoftLink] - [" + WCAException.E_ETC +"] " + toString() + " osSoftLink.close Error = " + ignore2.toString()); } } // 20200825 End sockSoftLink.close(); } else { return; } } catch (IOException ioe) { myLog.logMsg(MyLog.ERROR, "closeSoftLink] - [" + WCAException.E_ETC + "] Error = " + ioe.toString()); adapter_logger.error("closeSoftLink] - [" + WCAException.E_ETC +"] " + toString() + " Error = " + ioe.toString()); } // 어댑터 상태 체크 myLog.logMsg(MyLog.DEBUG, "setAdapterStatus] setting"); setAdapterStatus(true); myLog.logMsg(MyLog.DEBUG, "setAdapterStatus] ending"); // 미처리 트랜잭션 출력 traceRemainTransaction(); // 백업 전환 checkBackupConversion(); } finally { myLog.logMsg(MyLog.INFO, "socketClose] SessStat = SESS_STAT_NOTCONN"); nSessStat = WCADefine.SESS_STAT_NOTCONN; } } /** * 1. 기능 : 자동 백업 전환 * 2. 처리 개요 : * 3. 주의사항 **/ private void checkBackupConversion() { try { if (bRunning && !isBackupSessionPool()) { // 20091005 Start // 백업 Enable Flag가 false 이면 백업 전환 처리를 하지 않는다. if (bBackupEnableFlag == false) { myLog.logMsg(MyLog.WARN, "checkBackupConversion] - bBackupEnableFlag is " + bBackupEnableFlag); return; } // 20091005 End // 20091005 Start /* // 백업 모드 이면 return if (snaAdapter.getBackupMode(sNodeName, sGroupCode)) return; */ // 20091005 End myLog.logMsg(MyLog.DEBUG, "setWCAAutoBackup] starting "); int nConnectedSessNum = snaAdapter.getConnectedNormalSessNum(sNodeName, sGroupCode); myLog.logMsg(MyLog.DEBUG, "setWCAAutoBackup] nConnectedSessNum = " + nConnectedSessNum); if (nConnectedSessNum == 0) { snaAdapter.setWCAAutoBackup(sNodeName, sGroupCode); setAdapterStatus(true); } myLog.logMsg(MyLog.DEBUG, "setWCAAutoBackup] ending "); } } catch (WCAException e) { myLog.logMsg(MyLog.ERROR, "closeSoftLink] - [" + e.getErrorReturnCode() + "] Error = " + e.toString()); adapter_logger.error("closeSoftLink] - [" + e.getErrorReturnCode() +"] " + toString() + " Error = " + e.toString()); } } /** * 1. 기능 : Softlink input/output stream close * 2. 처리 개요 : * 3. 주의사항 **/ public void closeLogStream() { // 20200825 Start // myLog.closeLogStream(); // myTrc.closeLogStream(); if (myLog != null) { myLog.closeLogStream(); } if (myTrc != null) { myTrc.closeLogStream(); } // 20200825 End } int setInt(byte[] buf, int val, int idx) { buf[idx++] = (byte)((val & 0xff000000) / 0x1000000); buf[idx++] = (byte)((val & 0x00ff0000) / 0x10000); buf[idx++] = (byte)((val & 0x0000ff00) / 0x100); buf[idx++] = (byte)(val & 0x000000ff); return 4; } byte[] setInt(int val) { byte[] buf = new byte[4]; int idx = 0; buf[idx++] = (byte)((val & 0xff000000) / 0x1000000); buf[idx++] = (byte)((val & 0x00ff0000) / 0x10000); buf[idx++] = (byte)((val & 0x0000ff00) / 0x100); buf[idx++] = (byte)(val & 0x000000ff); return buf; } int setInt2(byte[] buf, int val, int idx) { buf[idx++] = (byte)(val & 0x000000ff); buf[idx++] = (byte)((val & 0x0000ff00) / 0x100); buf[idx++] = (byte)((val & 0x00ff0000) / 0x10000); buf[idx++] = (byte)((val & 0xff000000) / 0x1000000); return 4; } static int getInt(byte[] buf, int idx) { int b1 = 0, b2 = 0, b3 = 0, b4 = 0; b1 = (buf [idx] >= 0) ? buf[idx] : 0x100 + buf[idx]; b2 = (buf [idx + 1] >= 0) ? buf[idx + 1] : 0x100 + buf[idx + 1]; b3 = (buf [idx + 2] >= 0) ? buf[idx + 2] : 0x100 + buf[idx + 2]; b4 = (buf [idx + 3] >= 0) ? buf[idx + 3] : 0x100 + buf[idx + 3]; return b1 * 0x1000000 + b2 * 0x10000 + b3 * 0x100 + b4; } }