package com.eactive.eai.adapter.wca;

import com.eactive.eai.adapter.wca.cfg.SessionGroupDataEx;
import com.eactive.eai.adapter.wca.global.WCADefine;
import com.eactive.eai.common.util.Logger;

import java.util.LinkedList;

/** 
* 1. 기능 :  WCA 세션 풀 정보
* 2. 처리 개요 : 
*       - LU 그룹별로 풀이 생성된다.
* 3. 주의사항 
*
* @author  : 
* @version : v 1.0.0
* @see     : 
* @since   : 2005. 6. 22. 오후 5:03:52
*/  
public class WCASessionPool {  
    /**
     * SNAAdapter 트레이스 로깅을 위한 logger 
     */  
    Logger trc_logger = Logger.getLogger(Logger.LOGGER_ADAPTER);
     /**
     * SNAAdapter critical한 정보 로깅을 위한 logger 
     */
    Logger adapter_logger = Logger.getLogger(WCADefine.ADAPTER_LOGGER_NAME);
    
    // 20090810 Start
    private String		sNodeName			= "";		// Softlink Host Name
    // 20090810 End
    
    private String		sIpAddr             = null;     // Softlink Ip 주소                
    private int 		nPortNo             = 0;        // SoftLink Port 번호    
    private int			nSessNum            = 0;        // WCA 세션 수
    private String 		sAdapterGroupName   = null;     // 어댑터 그룹 이름
    private String 		sAdapterName        = null;     // 어댑터 이름
    private String 		sGroupCode          = null;     // LU 그룹 이름
    
    private int			nLocalSessionIdx    = 0;        // Pool에 설정된 세션 수
    public LinkedList	listWCASession      = null;     // Pool에 설정된 세션 리스트
    
    private String 		sAutoBackupCvsYN    = null;      // 자동 BACKUP 모드 (Y: yes , N: No)
    
    // BACKUP 전환 FLAG를 하나만 세팅 --> 수동 백업 복귀시 무조건 정상세션으루 전환하기 위함
    private boolean    	bBackupMode         = false;     // BACKUP 전환 FLAG
    
    // 20090810 Start
    private boolean 	bBackupEnableFlag 	= true;		 // 백업 기능 사용 가능 여부
    // 20090810 End 
    
    private boolean     bBackupSessionPool  = false;     // Backup Pool 여부 (true: 백업 세션)
    
    private boolean		bLogYN              = true;      // 로깅 여부
    private int  		nLogLevel           = 1;         // 로그 레벨
    private int  		nLogSize            = 4;         // 로그 파일 사이즈 
    
    private int         tran_timeout        = WCADefine.DEFAULT_TRANSACTION_TIMEOUT ;  // 트랜잭션 타임아웃
    
    private boolean     isStarted           = false;     // Pool 동작 여부 (true : 동작중)
    
    // 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. 기능 : WCA 세션 POOL Constructor
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @param sIpAddr            Softlink Ip 주소
    * @param nPortNo            SoftLink Port 번호
    * @param nSessId            WCA 세션 수       
    **/
    public WCASessionPool(String sIpAddr, int nPortNo, int nSessNum) {
        this.sIpAddr = sIpAddr;
        this.nPortNo = nPortNo;
        this.nSessNum = nSessNum;
        listWCASession = new LinkedList();
    }
    
   /** 
    * 1. 기능 : 세션 Pool 정보 설정
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @param    sAdapterGroupName  어댑터 그룹 이름
    * @param    sAdapterName       어댑터 이름
    * @param    sGrpCode           LU 그룹 이름
    **/     
	public void setSessionPoolInfo(String sAdapterGroupName, String sAdapterName, String sGroupCode) {
	    this.sAdapterGroupName  = sAdapterGroupName;
        this.sAdapterName       = sAdapterName;
	    this.sGroupCode         = sGroupCode;
	}
    
    
    /** 
    * 1. 기능 : 세션 Pool 정보 반환
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @return 세션 Pool 정보
    **/       
    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append(" " + sNodeName + "-" + sGroupCode );
        if (bBackupSessionPool) { sb.append(":BACAKUP "); }
        else { sb.append(" "); }
        return sb.toString();
    }
    
    /** 
    * 1. 기능 : 어댑터 그룹 이름 반환
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @return    어댑터 그룹 이름
    **/ 
    public String getAdapterGroupName() {
        return sAdapterGroupName;        
    }
    
    /** 
    * 1. 기능 : 어댑터 이름 반환
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @return    어댑터 이름
    **/ 
    public String getAdapterName() {
        return sAdapterName;        
    }
    
    /** 
    * 1. 기능 : Softlink Ip 주소 반환
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @return    Softlink Ip 주소 반환
    **/ 
    public String getHostName() {
        return sIpAddr;
    }
    
    /** 
    * 1. 기능 : Softlink Port 반환
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @return    Softlink Ip Port 반환
    **/ 
    public int getPort() {
        return nPortNo;        
    }
    
    /** 
    * 1. 기능 : LU 그룹 이름 반환 
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @return    LU 그룹 이름
    **/ 
    public String getGroupCode() {
        return sGroupCode;        
    }    
    
    /** 
    * 1. 기능 : WCA 세션 수 반환
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @return    WCA 세션 수 반환
    **/ 
    public int getSessNum() {
        return nSessNum;        
    }
    
    /** 
    * 1. 기능 : Sotlink 세션 정보 설정
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @param    sIpAddr         Softlink Ip 주소  
    * @param    nPortNo         SoftLink Port 번호    
    * @param    nSessNum        WCA 세션 수
    **/   
    public void setSessionInfo(String sNodeName, String sIpAddr, int nPortNo, int nSessNum) {
    	this.sNodeName = sNodeName;
        this.sIpAddr = sIpAddr;
        this.nPortNo = nPortNo;
        this.nSessNum = nSessNum;
    }
    
    /** 
    * 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. 기능 : 세션 Pool이 동작 여부 반환
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @return    세션 Pool이 동작 여부
    **/ 
    public boolean isStarted() {
        return isStarted;
    }    
    

    /** 
    * 1. 기능 : 로그 설정
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @param    bLogYN       로깅 여부
    * @param    nLogLevel    로깅 레벨
    * @param    nLogSize     로깅 파일 사이즈
    **/  
    public void setLogInfo(boolean bLogYN, int nLogLevel, int nLogSize) {
        this.bLogYN = bLogYN; 
        this.nLogLevel = nLogLevel;
        this.nLogSize = nLogSize;
    }   
    
    /** 
     * 1. 기능 : 세션 정보 갱신
     * 2. 처리 개요 : 
     * 3. 주의사항 
     * 
     * @param    sessgroup    LU 세션 그룹 정보 
     **/
    public void updateLuGroupInfoEx(SessionGroupDataEx sessgroup) {
    	WCASession 	wcaSession = null;
    	
    	String		sLogStr = "[" + sNodeName + "][" + sGroupCode + "]";
    	
        if (bBackupSessionPool) {
            sLogStr += "[BACAKUP]";
        }
    	
    	// 로컬 세션 Pool인 경우
        if (!isBackupSessionPool()) {
        	adapter_logger.warn("WCASessionPool:updateLuGroupInfoEx> " + sLogStr + " 세션 정보 설정, Value = [" + sessgroup.getNodeName() + "][" + 
        		sessgroup.getSoftLinkSevrName() + "][" + sessgroup.getPort() + "][" + sessgroup.getSessionCnt() + "]");                	
        	setSessionInfo(sessgroup.getNodeName(), sessgroup.getSoftLinkSevrName(),  sessgroup.getPort(), sessgroup.getSessionCnt());
        	
        	adapter_logger.warn("WCASessionPool:updateLuGroupInfoEx> " + sLogStr + " 백업 전환 모드 설정");        	
            setBackupCvsInfo(sessgroup.getBackupCvsMode());
        }
        // 백업 세션 Pool인 경우
        else {
        	adapter_logger.warn("WCASessionPool:updateLuGroupInfoEx> " + sLogStr + " 백업 세션 정보 설정, Value = [" + sessgroup.getNodeName() + "][" + 
        		sessgroup.getBackupNodeName() + "][" + sessgroup.getBackupPort() + "][" + sessgroup.getSessionCnt() + "]");                	
            setSessionInfo(sessgroup.getNodeName(), sessgroup.getBackupNodeName(), sessgroup.getBackupPort(), sessgroup.getSessionCnt());
        }
         
        adapter_logger.warn("WCASessionPool:updateLuGroupInfoEx> " + sLogStr + "  로그 관련 정보 설정, Value = [" + sessgroup.isLogWritable() + "][" + 
        		sessgroup.getLogLevel() + "][" + sessgroup.getLogSize() + "]");        
        setLogInfo(sessgroup.isLogWritable(), sessgroup.getLogLevel(), sessgroup.getLogSize());
        
        adapter_logger.warn("WCASessionPool:updateLuGroupInfoEx> " + sLogStr + "  트랜잭션 타임아웃 값 설정, Value = " + sessgroup.getTranTimeout());        
        setTranTimeout(sessgroup.getTranTimeout());
        
        // 백업 세션 사용 가능 여부 플래그 설정 
        adapter_logger.warn("WCASessionPool:updateLuGroupInfoEx> " + sLogStr + "  백업 세션 사용 가능 여부 플래그 설정, Value = " + sessgroup.getBackupEnableFlag());                
        setBackupEnableFlag(sessgroup.getBackupEnableFlag());
        
        // 세션 풀 안에 존재하는 WCA Session 오브젝트 정보 갱니
        for (int i = 0; i < listWCASession.size(); i++) {
        	wcaSession = (WCASession)listWCASession.get(i);
        	if (wcaSession == null) {
        		continue;
        	}
        	
            wcaSession.updateSessionInfoEx(sessgroup);    
        }        
    }
       
    /** 
     * 1. 기능 : WCA APP CODE 정보 갱신 (updateLuGroupInfoEx 함수를 참조하여 개발)
     * 2. 처리 개요 : 
     * 3. 주의사항 
     * 
     * @param    sessgroup    LU 세션 그룹 정보 
     **/
    public void updateWcaAppCodeEx() {
    	WCASession 	wcaSession = null;
    	
        // 세션 풀 안에 존재하는 WCA Session 오브젝트 정보 갱니
        for (int i = 0; i < listWCASession.size(); i++) {
        	wcaSession = (WCASession)listWCASession.get(i);
        	if (wcaSession == null) {
        		continue;
        	}
        	
            wcaSession.updateWcaAppCodeEx();    
        }        
    }
    
    /** 
    * 1. 기능 : 백업 정보 설정
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @param    sAutoBackupCvsYN   자동 백업 전환 여부
    **/  
    public void setBackupCvsInfo(String sAutoBackupCvsYN) {
        this.sAutoBackupCvsYN = sAutoBackupCvsYN;
    }
   
    public String getBackupCvsInfo() {
    	return sAutoBackupCvsYN;
    }
    
    /** 
    * 1. 기능 : 백업 세션 여부 설정 (true: 백업 세션)
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @param    flag       백업 세션 여부
    **/    
    public void setBackupSessionPool(boolean flag) {
        bBackupSessionPool = flag;
    }
    
    /** 
    * 1. 기능 : 백업 세션 여부 반환 (true: 백업 세션)
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @return    백업 세션 여부
    **/  
    public boolean isBackupSessionPool() {
        return bBackupSessionPool;
    }
    
    /** 
    * 1. 기능 : 수동 백업 세션 전환 설정 (true : 백업 세션, false : 세션 복구)
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @param    flag      백업 전환 모드
    **/
    public void setManualBackupMode(boolean flag) {
        // bManualBackupMode = flag;
        bBackupMode = flag;
        
        if (flag == true) {
            adapter_logger.warn("WCASessionPool:setManualBackupMode> " + toString() + "수동 백업모드로 전환되었습니다.");
        }
        else {
            adapter_logger.warn("WCASessionPool:setManualBackupMode> " + toString() + "수동 백업모드로 복구되었습니다.");
        }
    }
    
    /** 
    * 1. 기능 : 자동 백업 세션 전환 설정 (true : 백업 세션, false : 세션 복구)
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @param    flag      백업 전환 모드
    **/
    public void setAutoBackupMode(boolean flag) {
        if (sAutoBackupCvsYN.equalsIgnoreCase(WCADefine.WCA_AUTO_BACKUP_CVS_MODE_YES)) {
            bBackupMode = flag;
            if (flag == true) {
                if (adapter_logger.isInfo()) { adapter_logger.info(toString() + "자동 백업 모드 메시지 수신하었습니다."); }
            }
            else {
                if (adapter_logger.isInfo()) { adapter_logger.info(toString() + "자동 백업 복구 메세지 수신하였습니다."); }
            }
        }
        else {
            if (flag == true) {
                if (adapter_logger.isInfo()) { adapter_logger.info(toString() + "자동 백업 모드 메시지 수신하었습니다. 자동  백업 모드가 아닙니다."); }
            }
            else {
                if (adapter_logger.isInfo()) { adapter_logger.info(toString() + "자동 백업 복구 메세지 수신하였습니다. 자동  백업 모드가 아닙니다."); }
            }
        }
    }
    
    public void setWCAAutoBackup() {   
        if (sAutoBackupCvsYN.equalsIgnoreCase(WCADefine.WCA_AUTO_BACKUP_CVS_MODE_YES)) {
            bBackupMode = true;
            adapter_logger.warn(toString() + "가용율이 0입니다. 백업 모드로 전환합니다.");
        }
        else {
            adapter_logger.warn(toString() + "가용율이 0입니다. 자동  백업 모드가 아닙니다.");
        }        
    }

    /** 
    * 1. 기능 : 백업 모드로 전환되었는지 판단 (true: 백업 세션)
    * 2. 처리 개요 : 
    *     다음의 경우 백업 모드로 전환 
    *     - 수동 백업 전환 메세지 수신한 경우
    *     - 자동 백업 모드가 YES 이고 자동 백업 전환 메세지 수신한 경우 
    * 3. 주의사항 
    * 
    * @return    백업 전환 여부
    **/
    public boolean getBackupMode() {
        return bBackupMode;
    }
   
    /** 
    * 1. 기능 :  Softlink와 연결된 세션수를 반환
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @return    Softlink와 연결된 세션수
    **/
    public int getConnectedSessNum()  {
        int			nTotalSessNum = 0;
        WCASession 	wcaSession = null;
        
        for (int i = 0; i < nSessNum; i++) {
            if (listWCASession.size() <= i) { break; }
	        wcaSession = (WCASession)listWCASession.get(i);
	        nTotalSessNum += wcaSession.getConnectedSessNum();
        }
        
        return nTotalSessNum;
    }
    
    /** 
    * 1. 기능 :  Softlink와 설정된 세션수를 반환
    * 2. 처리 개요 : 
    * 3. 주의사항 
    * 
    * @return    Softlink와 설정된 세션수
    **/
    public int getConfiguredSessNum()  {
       return nSessNum;
    }
    
    /** 
    * 1. 기능 :  세션 Pool 초기화
    * 2. 처리 개요 : 
    *          - WCA 세션 수 만큼 WCASession을 생성 및 초기화한다.
    *          - WCA 세션 리스트에 추가한다.
    *          - isStarted를 true 로 설정한다.
    * 3. 주의사항
    * 
    **/
    // 20200603 Start 
    // 백업 세션 연결 처리를 위해서 WCA Session Thread에 의해서 호출되는 경우, 백업 세션이 정해진 세션수보다 늘어나는 것을 방지하기 위해서  synchronized 함수로 변경
    // public void initAndStartWcaSessionInSessionPool() {
    public synchronized void initAndStartWcaSessionInSessionPool() {
    // 20200603 end    	
        WCASession wcaSession = null;    
        int wcsSessionCount = 0;
                
        // 20200603 Start
        // isStarted 값 설정 위치를 함수 시작 위치로 이동
        adapter_logger.error("WCASessionPool:initAndStartWcaSessionInSessionPool> " + toString() + ", Start, Set isStarted = true");        
        isStarted = true;
        // 20200603 End
        
        for (int i = 0; i < nSessNum; i++) {
            // 20200603 Start
        	synchronized (listWCASession) {
        		wcsSessionCount = listWCASession.size();
        	}
        	
    		if (wcsSessionCount >= nSessNum) {
    			adapter_logger.error("WCASessionPool:initAndStartWcaSessionInSessionPool> " + toString() + ", Already Max Session Count");
    			break;
    		}        	
            // 20200603 End
        	
	        wcaSession = new WCASession(sIpAddr, nPortNo, sAdapterGroupName, sAdapterName, sGroupCode, i);
            wcaSession.setBackupSessionPool(bBackupSessionPool);
            wcaSession.setLogInfo(bLogYN, nLogLevel, nLogSize);
            wcaSession.setTranTimeout(tran_timeout);
            
            // 20090810 Start
            wcaSession.setNodeName(sNodeName);
            wcaSession.setBackupEnableFlag(bBackupEnableFlag);
            // 20090810 End
            
	        wcaSession.initWCASession();
	        
	        adapter_logger.error("WCASessionPool:initAndStartWcaSessionInSessionPool> " + toString() + ", Add wcaSession to listWCASession");
	        
	        synchronized (listWCASession) {
	        	listWCASession.addLast(wcaSession);
	        }
        }
        
        // 20200603 Start
        // isStarted 값 설정 위치를 함수 시작 위치로 이동
        /*
        adapter_logger.error("WCASessionPool:initAndStartWcaSessionInSessionPool> " + toString() + ", Set isStarted = true");        
        isStarted = true;
        */
        // 20200603 End        
        
        return;
    }
     
    /** 
     * 1. 기능 :  세션 수 추가
     * 2. 처리 개요 : 
     *          - 증가한 세션수 만큼 WCASession을 생성 및 초기화한다.
     *          - WCA 세션 리스트에 추가한다.
     * 3. 주의사항
     * 
     **/
    public void increaseSessionPool(int nOldSessNum, int nNewSessNum) {
        WCASession wcaSession = null;
        
        if (adapter_logger.isDebug()) { adapter_logger.debug(toString() + " increaseSessionPool is starting"); }
        
        for (int i = nOldSessNum; i < nNewSessNum; i++) {
	        wcaSession = new WCASession(sIpAddr, nPortNo, sAdapterGroupName, sAdapterName, sGroupCode, i);
            wcaSession.setBackupSessionPool(bBackupSessionPool);
            wcaSession.setLogInfo(bLogYN, nLogLevel, nLogSize);
            wcaSession.setTranTimeout(tran_timeout);
            
	        wcaSession.initWCASession();
	        
	        synchronized (listWCASession) {
	        	listWCASession.addLast(wcaSession);
	        }
        }
        
        adapter_logger.warn("WCASessionPool:increaseSessionPool> " + toString() + " " + (nNewSessNum - nOldSessNum) + " 세션이 증가하였습니다. ");
    }
    
    /** 
    * 1. 기능 :  세션 Pool 종료
    * 2. 처리 개요 : 
    *          - WCA 세션 리스트에 등록된 WCA 세션의 stopAdapter를 호출한다.
    * 3. 주의사항
    **/
    public void stopAdapter() {
        String		strLogPrefix = getLogPrefix();
             
        adapter_logger.warn("WCASessionPool:stopAdapter> " + strLogPrefix + " Start To Stop WCA Session List");
        adapter_logger.warn("WCASessionPool:stopAdapter> " + strLogPrefix + " WCA Session Count = " +  listWCASession.size());
        
        for (int i = 0; i < listWCASession.size(); i++) {
        	WCASession wcaSession = (WCASession)listWCASession.get(i);
            wcaSession.stopAdapter();
        }
        
        adapter_logger.warn("WCASessionPool:stopAdapter> " + strLogPrefix + " Clear WCA Session List");
        synchronized (listWCASession) {
        	listWCASession.clear();
        }
        
        adapter_logger.warn("WCASessionPool:stopAdapter> " + strLogPrefix + " Set isStarted Flag to False");        
        isStarted = false;
        
        adapter_logger.warn("WCASessionPool:stopAdapter> " + strLogPrefix + " Start To Stop WCA Session List");        
    }
    
    public String getLogPrefix() {
        StringBuffer sbLogPrefix = new StringBuffer();
        sbLogPrefix.append("[" + sAdapterGroupName + "][" + sNodeName + "]["+ sGroupCode + "]");
        if (bBackupSessionPool) {
        	sbLogPrefix.append("[BACAKUP]");
        }
        
        return sbLogPrefix.toString();
    }
    
    /** 
    * 1. 기능 :  INBOUND 핸들러 등록
    * 2. 처리 개요 : 
    *          - WCA 세션 리스트에 등록된 WCA 세션에 INBOUND 핸들러 등록한다.
    * 3. 주의사항
    **/
    public void registerEventHandler(Object objHandler) {
        int				i;
        WCASession		wcaSession = null;
        
        for (i = nLocalSessionIdx; i < listWCASession.size(); i++) {
            wcaSession = (WCASession)listWCASession.get(i);
            wcaSession.registerEventHandler(objHandler);
        }        
        
        return;
    }
    
    
    /** 
    * 1. 기능 :  WCA 세션을 반환
    * 2. 처리 개요 : 
    *      - 세션 Pool이 송신 가능한지 판단한다. (트랜잭션 모드가 "S" 일경우)
    *      - WCA 세션풀내에서 이용가능한 세션을 부하 분산울 위해서 라운드 로빈 방식으로 구한다.
    * 3. 주의사항
    * 
    * @return WCASession  WCA 세션 
    **/
    public synchronized WCASession getWCASessionInSessionPool() {
        WCASession	wcaSession = null;
        int			i = 0;
                
        // 해당 세션이 없을 경우
        if (listWCASession.size() == 0) {
            if (trc_logger.isInfo()) {
            	trc_logger.info("getWCASessionInSessionPool] - listWCASession Size = 0 " + toString());            
            }
            
            return null;
        }
        
        // WCA 세션 풀에서 부하 분산을 위해서 라운드 로빈 방식으로 WCA 세션을 구함
        nLocalSessionIdx = nLocalSessionIdx % listWCASession.size();
        for (i = nLocalSessionIdx; i < listWCASession.size(); i++) {
            wcaSession = (WCASession)listWCASession.get(i);
            if (wcaSession.isAvailable()) {
                nLocalSessionIdx++;
                return wcaSession;                    
            }
        }
        
        if (i == listWCASession.size()) {
            for (i = 0; i < nLocalSessionIdx; i++) {
                wcaSession = (WCASession)listWCASession.get(i);
                if (wcaSession.isAvailable()) {
                    nLocalSessionIdx++;
                    return wcaSession;
                }
            }                
        }
        
        nLocalSessionIdx++;
        //trc_logger.error("getWCASessionInSessionPool] Available Session doesn't Exist...." + toString() );
        
        return null;
    }

	public int getPortNo() {
		return nPortNo;
	}

	public void setPortNo(int nPortNo) {
		this.nPortNo = nPortNo;
	}
}
