Files
elink-online-common/src/main/java/com/eactive/eai/adapter/wca/WCASessionThread.java
T
2026-03-03 14:09:55 +09:00

2048 lines
88 KiB
Java

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;
}
}