This commit is contained in:
Rinjae
2025-09-05 18:57:45 +09:00
commit aacc1a389e
1229 changed files with 167963 additions and 0 deletions
@@ -0,0 +1,70 @@
package com.eactive.eai.common.session;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* 1. 기능 : Cache정보를 표현하는 Java Value Object 클래스. 2. 처리 개요 : Cache 정보를 정의한다. 3.
* 주의사항
*
* @author :
* @version : v 1.0.0
* @see : 관련 기능을 참조
* @since :
*/
public class CacheInfoVO implements Serializable {
private String name;
private List<String> keys;
private long size;
private long timeToLive;
/**
* 1. 기능 : EAI서비스 코드를 초기화하는 생성자 함수 2. 처리 개요 : EAI 서비스 코드를 초기화한다. 3. 주의사항
*
* @param eaiInstCd
* EAI 서버인스턴스명
* @param eaiSvcCd
* EAI 서비스 코드
**/
public CacheInfoVO() {
keys = new ArrayList<String>();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getKeys() {
return keys;
}
public void setKeys(List<String> keys) {
this.keys = keys;
}
public long getTimeToLive() {
return timeToLive;
}
public long getTimeToLiveSeconds() {
return timeToLive / 1000;
}
public void setTimeToLive(long timeToLive) {
this.timeToLive = timeToLive;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
}
@@ -0,0 +1,22 @@
package com.eactive.eai.common.session;
import java.io.Serializable;
public class CacheStoreObject implements Serializable {
private static final long serialVersionUID = 1L;
private String message;
private long expirationTime;
public CacheStoreObject(String message, long expirationTime) {
this.message = message;
this.expirationTime = expirationTime;
}
public String getMessage() {
return message;
}
public boolean isExpired() {
return System.currentTimeMillis() > expirationTime;
}
}
@@ -0,0 +1,514 @@
package com.eactive.eai.common.session;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang.StringUtils;
import org.java_websocket.WebSocket;
import org.json.simple.JSONObject;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import com.eactive.eai.adapter.websocket.WebSocketSessionManager;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.property.PropertyLoginKeys;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.sessioninfo.SessionHistoryDTO;
import com.eactive.eai.common.sessioninfo.SessionHistoryVO;
import com.eactive.eai.common.sessioninfo.SessionInfoVO;
import com.eactive.eai.common.sessioninfo.SessionInfoVO.Status;
import com.eactive.eai.common.util.DatetimeUtil;
import com.eactive.eai.common.util.Logger;
public class ChannelSessionFacade {
public enum LogoutType {
Logout, AutoLogout, ForceLogout, WebSocketTimeout, DateChange, ServerDown
}
private static ChannelSessionFacade instance;
private Logger logger;
private SessionManager sessionManager;
private WebSocketSessionManager webSocketSessionManager;
private SessionStatusManager sessionStatusManager;
private ExecutorService logoutRunnerExecutor;
private static final Integer DEFAULT_LOGOUT_MIN_THREAD_COUNT = 10;
public static ChannelSessionFacade getInstance() {
if (instance == null) {
synchronized (ChannelSessionFacade.class) {
if (instance == null) {
instance = new ChannelSessionFacade();
instance.logger = Logger.getLogger(Logger.LOGGER_ADAPTER);
instance.sessionManager = SessionManager.getInstance();
instance.webSocketSessionManager = WebSocketSessionManager.getInstance();
instance.sessionStatusManager = SessionStatusManager.getInstance();
PropManager pManager = PropManager.getInstance();
if (pManager.isContainProperties(PropertyLoginKeys.LOGIN)){
Properties loginProp = pManager.getProperties(PropertyLoginKeys.LOGIN);
int logoutMaxThreadCount = Integer.parseInt(loginProp.getProperty(PropertyLoginKeys.LOGOUT_MAX_THREAD, "30"));
int logoutMinThreadCount = logoutMaxThreadCount < DEFAULT_LOGOUT_MIN_THREAD_COUNT ? logoutMaxThreadCount : DEFAULT_LOGOUT_MIN_THREAD_COUNT;
int logoutMaxQueueSize = Integer.parseInt(loginProp.getProperty(PropertyLoginKeys.LOGOUT_MAX_QUEUE, "500"));
LinkedBlockingQueue<Runnable> runnerQueue = new LinkedBlockingQueue<Runnable>(logoutMaxQueueSize);
instance.logoutRunnerExecutor =
new ThreadPoolExecutor(
logoutMinThreadCount, logoutMaxThreadCount, 60000L, TimeUnit.MILLISECONDS, runnerQueue, new CustomizableThreadFactory("LogoutRunner-"));
}
}
}
}
return instance;
}
public void login(String userId, String uuid, JSONObject resultJson) {
logger.debug("login] userId : " + userId, " uuid : " + uuid);
PropManager pManager = PropManager.getInstance();
Properties loginProp = pManager.getProperties(PropertyLoginKeys.LOGIN);
/** PostBank
String KEY_USER_NM = loginProp.getProperty(PropertyLoginKeys.LOGIN_USER_NM);
// 소속국
String KEY_BRN_CD = loginProp.getProperty(PropertyLoginKeys.LOGIN_BRN_CD);
String KEY_BRN_NM = loginProp.getProperty(PropertyLoginKeys.LOGIN_BRN_NM);
// 소속청
String KEY_ROFC_CD = loginProp.getProperty(PropertyLoginKeys.LOGIN_ROFC_CD);
// terminalId
String TERMINAL_ID = loginProp.getProperty(PropertyLoginKeys.LOGIN_TERMINAL_ID);
**/
EAIServerManager eaiServerManager = EAIServerManager.getInstance();
String serverName = eaiServerManager.getLocalServerName();
// String brncd = (String) resultJson.get(KEY_BRN_CD);
SessionVO sessionVo = new SessionVO();
sessionVo.setUuid(uuid);
sessionVo.setLoginUserId(userId);
sessionVo.setLoginInstId(serverName);
// sessionVo.setBrncd(brncd);
// sessionVo.setTerminalId((String) resultJson.get(TERMINAL_ID));
sessionManager.putLogin(userId, sessionVo);
sessionManager.putHttpLogin(uuid, sessionVo);
sessionManager.putWebSocketTimeout(userId, sessionVo);
SessionInfoVO sessionInfoVO = new SessionInfoVO(userId);
sessionInfoVO.setSessionId(uuid);
sessionInfoVO.setCreateTime(DatetimeUtil.getCurrentDateTime());
sessionInfoVO.setSessionStatus(SessionInfoVO.Status.active);
// sessionInfoVO.setUserName((String) resultJson.get(KEY_USER_NM));
// sessionInfoVO.setRofcCode((String) resultJson.get(KEY_ROFC_CD));
// sessionInfoVO.setBrnName((String) resultJson.get(KEY_BRN_NM));
// sessionInfoVO.setBrnCode(brncd);
// sessionInfoVO.setTerminalId((String) resultJson.get(TERMINAL_ID));
sessionStatusManager.manageStatus(sessionInfoVO);
}
public void logout(String userId, String uuid, boolean logoutTransaction, LogoutType logoutType) {
sessionManager.removeLogin(userId);
sessionManager.removeHTTPLogin(uuid);
sessionManager.removeWebSocketTimeout(userId); // logout시 timeout 해제
logger.info(userId + " 사용자 연결 끊어짐으로 로그아웃 거래 수행.");
if(logoutTransaction) {
logoutRunnerExecutor.submit(() -> {
try {
sendLogoutTransaction(userId, uuid, logoutType);
} catch (Exception e) {
logger.error("sendLogoutTransaction Runner error. USERID{"+userId+"}", e);
}
});
}
sessionStatusManager.manageLoginStatus(userId);
}
public void logout(String userId, String uuid, boolean logoutTransaction, LogoutType logoutType, CountDownLatch latch) {
sessionManager.removeLogin(userId);
sessionManager.removeHTTPLogin(uuid);
sessionManager.removeWebSocketTimeout(userId); // logout시 timeout 해제
logger.info(userId + " 사용자 연결 끊어짐으로 로그아웃 거래 수행.");
if(logoutTransaction) {
logoutRunnerExecutor.submit(() -> {
try {
sendLogoutTransaction(userId, uuid, logoutType);
latch.countDown();
logger.info("Remove Cache And Logout. key= " + userId + "remain=" + latch.getCount());
} catch (Exception e) {
logger.error("sendLogoutTransaction Runner error. USERID{"+userId+"}", e);
}
});
} else {
latch.countDown();
logger.info("cache has been removed but not a logoutTransaction. key= " + userId + "remain=" + latch.getCount());
SessionHistoryLogger.getInstance().log(
new SessionHistoryDTO("LOGOUT( "+userId+" )NOT-TRANSACTION", SessionHistoryVO.convertLogoutType_EnumToString(logoutType), "N", uuid, null, false));
}
sessionStatusManager.manageLoginStatus(userId);
}
public void removeFromLoginCache(String userId) {
logger.debug("removeFromLoginCache] userId : " + userId);
sessionManager.removeLogin(userId);
}
public void removeFromHttpCache(String uuid) {
logger.debug("removeFromHttpCache] uuid : " + uuid);
sessionManager.removeHTTPLogin(uuid);
}
public void removeFromHttpCacheByUserId(String userId) {
logger.debug("removeFromHttpCacheByUserId] userId : " + userId);
for(String uuid : sessionManager.getHttpLoginCache().getKeys()) {
SessionVO httpLogin = sessionManager.getHttpLogin(uuid);
if(StringUtils.equals(userId, httpLogin.getLoginUserId())) {
sessionManager.removeHTTPLogin(uuid);
}
}
}
public void onAttachWebSocketSession(String adapterGroupName, WebSocket conn, String userId) {
logger.debug("onAttachWebSocketSession] adapterGroupName : " + adapterGroupName + " userId : " + userId);
SessionVO sessionVo = SessionManager.getInstance().getLogin(userId);
webSocketSessionManager.sessionLogin(adapterGroupName, conn, userId);
// WebSocket connection instance
String serverName = EAIServerManager.getInstance().getLocalServerName();
sessionVo.setWsInstId(serverName);
sessionVo.setWsAdapterGroupName(adapterGroupName);
sessionManager.putLogin(userId, sessionVo); // refresh
sessionManager.putHttpLogin(sessionVo.getUuid(), sessionVo); // refresh
sessionManager.removeWebSocketTimeout(userId); // webSocket 연결 시 timeout 해제
SessionInfoVO sessionInfoVO = new SessionInfoVO(userId);
sessionInfoVO.setWsocInstance(serverName);
sessionInfoVO.setWsocRemoteAddr(conn.getRemoteSocketAddress().toString());
sessionInfoVO.setWsocSessionStatus(Status.active);
sessionStatusManager.manageStatus(sessionInfoVO);
}
public void onDetachWebSocketSession(String adapterGroupName, WebSocket conn) {
logger.debug("onDetachWebSocketSession] adapterGroupName : " + adapterGroupName + " connection : " + conn.getRemoteSocketAddress());
webSocketSessionManager.onCloseEvent(adapterGroupName, conn);
}
public void closeWebSocketByUserId(String userId, boolean logoutTransaction, LogoutType logoutType) {
logger.debug("closeWebSocketByUserId] userId : " + userId + " logoutTransaction : " + logoutTransaction + " logoutType : " + logoutType.name());
for (String adapterGroupName : webSocketSessionManager.getAdapterGroupNames()) {
try {
if (webSocketSessionManager.isContainKeys(adapterGroupName, userId)) {
WebSocket conn = webSocketSessionManager.getSession(adapterGroupName, userId);
if (conn != null) {
if (logger.isDebug()) {
logger.debug("Close WebSocket Connection : " + conn.getRemoteSocketAddress());
}
webSocketSessionManager.closeSession(adapterGroupName, userId);
} else {
logger.debug("closeWebSocketByUserId] userId ["+userId+"]connection is NULL. closeWebSocket skipped");
}
}
} catch (Exception e) {
// Logging And Skip
logger.error("closeSession Error : " + e.getMessage(), e);
continue;
}
}
if(logoutTransaction) {
logoutRunnerExecutor.submit(() -> {
try {
sendLogoutTransaction(userId, null, logoutType);
} catch (Exception e) {
logger.error("sendLogoutTransaction Runner error. USERID{"+userId+"}", e);
}
});
}
SessionStatusManager.getInstance().manageWebSocketStatus(userId, Status.inactive);
}
public void closeWebSocketByAdapterGroupAndUserId(String adapterGroupName, String userId, boolean logoutTransaction, LogoutType logoutType) {
if(webSocketSessionManager.getAdapterGroupNames().contains(adapterGroupName)) {
try {
WebSocket conn = webSocketSessionManager.getSession(adapterGroupName, userId);
if (conn != null) {
if (logger.isDebug()) {
logger.debug("Close WebSocket Connection : " + conn.getRemoteSocketAddress());
}
webSocketSessionManager.closeSession(adapterGroupName, userId);
} else {
logger.debug("closeWebSocketByUserId] userId ["+userId+"]connection is NULL. closeWebSocket skipped");
}
} catch (Exception e) {
// Logging And Skip
logger.error("closeSession Error : " + e.getMessage(), e);
}
}
if(logoutTransaction) {
logoutRunnerExecutor.submit(() -> {
try {
sendLogoutTransaction(userId, null, logoutType);
} catch (Exception e) {
logger.error("sendLogoutTransaction Runner error. USERID{"+userId+"}", e);
}
});
}
SessionStatusManager.getInstance().manageWebSocketStatus(userId, Status.inactive);
}
public void refreshLoginCache(String userId, SessionVO sessionVO) {
sessionManager.putLogin(userId, sessionVO);
}
public void refreshHttpLoginCache(String uuid, SessionVO sessionVO) {
sessionManager.putHttpLogin(uuid, sessionVO);
}
public void onDateChange() {
logger.debug("DateChange] Start");
webSocketSessionManager.closeSessionAll();
try {
removeAllLocalCache(false, LogoutType.DateChange);
} catch (Exception e) {
logger.error("removeAllLocalCache error.", e);
}
logger.debug("DateChange] End");
}
public void onServerDown() {
logger.debug("ServerDown] Start");
webSocketSessionManager.closeSessionAll();
try {
removeAllLocalCache(true, LogoutType.ServerDown);
} catch (Exception e) {
logger.error("removeAllLocalCache error.", e);
} finally { // onServerDown시 Executor와 sessionManager를 close한다.
if (logoutRunnerExecutor != null)
try {
logoutRunnerExecutor.shutdown();
} catch (Exception e) {
}
if (sessionManager != null)
try {
sessionManager.closeManager();
} catch (Exception e) {
}
}
if (logoutRunnerExecutor != null) {
logoutRunnerExecutor.shutdown();
}
logger.debug("ServerDown] End");
}
private void removeAllLocalCache(boolean logoutTransaction, LogoutType logoutType) throws InterruptedException {
List<String> loginCacheKeys = sessionManager.getLoginCache().getKeys();
CountDownLatch latch = new CountDownLatch(loginCacheKeys.size());
for(String loginKey : loginCacheKeys) {
SessionVO login = sessionManager.getLogin(loginKey);
if(login != null) {
String localServerName = EAIServerManager.getInstance().getLocalServerName();
String wsInstId = login.getWsInstId();
String loginInstId = login.getLoginInstId();
if((wsInstId == null && localServerName.equals(loginInstId))// http login 을 했는데 websocket 로그인이 안된경우
|| localServerName.equals(wsInstId)) { // stop 하는 인스턴스의 websocket을 구별해서
logout(login.getLoginUserId(), login.getUuid(), logoutTransaction, logoutType, latch);
} else {
latch.countDown();
logger.info("pass other instance. key= " + loginKey + "remain=" + latch.getCount());
}
} else {
latch.countDown();
logger.info("pass sessionVo is null. key= " + loginKey + "remain=" + latch.getCount());
}
}
boolean await = latch.await(180, TimeUnit.SECONDS);
if(await) {
logger.debug("removeAllLocalCache success. remain latch count : " + latch.getCount());
} else {
logger.warn("latch timeout occurred. remain count : " + latch.getCount());
}
}
private void sendLogoutTransaction(String userId, String uuid, LogoutType logoutType) throws Exception {
//
// String historyDstcd = SessionHistoryVO.convertLogoutType_EnumToString(logoutType);
//
// PropManager pManager = PropManager.getInstance();
// Properties loginProp = pManager.getProperties("LOGIN");
// Properties stdMessageProp = pManager.getProperties("STDMESSAGE");
// EAIServerManager serverManager = EAIServerManager.getInstance();
//// String envMode = System.getProperty(Keys.EAI_SYSTEMMODE);
// String envMode = serverManager.getSystemEnvTypeConvert();
//
// String logoutServiceId = loginProp.getProperty("LOGOUT_SERVICE_ID");
// String logoutInterfaceId = loginProp.getProperty("LOGOUT_INTERFACE_ID");
// String messageVersion = stdMessageProp.getProperty("VERSION");
//
// String currentTimeMills = DatetimeUtil.getCurrentTimeMillis();
//
// String systemCode = "MCC";
// String guid = UUIDGenerator.getGUID(systemCode);
// STDMessage stdmsg = new STDMessage();
// stdmsg.setData("systemHeader.VRSN", messageVersion); //버전
// stdmsg.setData("systemHeader.IPOP_DVSN_CD", "I"); //입력출력구분코드
// stdmsg.setData("systemHeader.FRST_GUID", guid); //최초GUID
// stdmsg.setData("systemHeader.GUID", guid); //GUID
// //stdmsg.setData("systemHeader.PRGR_SN", "1"); //진행일련번호
// //stdmsg.setData("systemHeader.TLGR_ENCRT_YN", "N"); //전문암호화여부
// stdmsg.setData("systemHeader.CHNL_DVSN_CD", "00"); //채널구분
// stdmsg.setData("systemHeader.IP_VRSN_DVSN_CD", "V4"); //IP버전구분코드
// stdmsg.setData("systemHeader.ENVR_INFO_DVSN_CD", envMode); //환경정보구분코드
// stdmsg.setData("systemHeader.FRST_DMND_APLC_SYS_CD", systemCode); //최초요청어플리케이션시스템코드
// stdmsg.setData("systemHeader.FRST_DMND_INTF_SYS_CD", systemCode); //최초요청인터페이스시스템코드
// stdmsg.setData("systemHeader.TRSM_SYS_CD", systemCode); //전송시스템코드
// stdmsg.setData("systemHeader.MCI_INTF_ID", logoutInterfaceId); //MCI_인터페이스ID
// stdmsg.setData("systemHeader.FRST_TLGR_DMND_DT", currentTimeMills); //최초전문요청일시
// stdmsg.setData("systemHeader.DMND_SYS_CD", systemCode); //요청시스템코드
// stdmsg.setData("systemHeader.TLGR_DMND_DT", currentTimeMills); //전문요청일시
// stdmsg.setData("systemHeader.DLNG_PRCS_DVSN_CD", "S"); //거래처리구분코드
//
// stdmsg.setData("systemHeader.RSPNS_RSLT_DVSN_CD", "N"); //응답결과구분코드
//
// //stdmsg.setData("systemHeader.MULTILNG_DVSN_CD", "ko"); //다국어구분코드
// stdmsg.setData("systemHeader.DLNG_ID", logoutServiceId); //거래ID
// //stdmsg.setData("systemHeader.RTRCN_DLNG_YN", "N"); //취소거래여부
// //stdmsg.setData("systemHeader.TLGR_TYP_DVSN_CD", "G"); //전문 유형코드
// //stdmsg.setData("systemHeader.LVOL_DAT_PRCS_DVSN_CD", "N"); //대량데이터처리구분코드
// //stdmsg.setData("systemHeader.LVOL_DAT_PRCS_SN", "0"); //대량데이터처리일련번호
// //stdmsg.setData("systemHeader.SMLT_DLNG_DVSN_CD", "G"); //시뮬레이션 거래 구분코드
// //stdmsg.setData("systemHeader.ACNT_MODE_DVSN_CD", "0"); //계정모드 구분코드
//
// //기존 대비 validation 추가 항목 - start - 20220310
// stdmsg.setData("systemHeader.FRST_DMND_SYS_IP_VAL", serverManager.getServerIp()); //최초요청시스템IP값
// stdmsg.setData("systemHeader.FRST_DMND_SYS_MAC_VAL", serverManager.getServerMac()); //최초요청시스템MAC값
// stdmsg.setData("systemHeader.TMOT_CD", "S"); //타임아웃코드
// //기존 대비 validation 추가 항목 - end - 20220310
//
// stdmsg.setData("commonHeader.USERID", userId); //사용자 ID
//
// //공통 헤더 셋팅 못함
// //청코드
// //국코드
// //취급청코드
// //취급국코드
//
// String body = "{\"USERID\":\""+userId+"\"}";
// String sendData = stdmsg.toJSONString(body);
//
// try {
// String eaiSvcCd = logoutInterfaceId + STDMessage.SEND_RECV_CD_SEND + STDMessage.DIRECTION_IN;
// EAIMessage eaiMsg = EAIMessageManager.getInstance().getEAIMessage(eaiSvcCd);
// if(eaiMsg == null){
// logger.error(eaiSvcCd+" 서비스가 존재하지 않음");
// return;
// }
// String adapterGroupName = eaiMsg.getCurrentSvcMsg().getPsvSysItfTp();
//
// AdapterGroupVO gvo = AdapterManager.getInstance().getAdapterGroupVO(adapterGroupName);
//
// // 어댑터가 사용중이 아니면 Skip한다.
// if (gvo == null || gvo.isUsedFlag() == false) {
// logger.error(adapterGroupName+" 어댑터가 등록되어있지 않거나 미사용 상태라 로그아웃 미수행");
// return;
// }
//
// AdapterVO avo = gvo.nextAdapterVO();
// if (avo == null){
// logger.error(adapterGroupName+"에 가용한 어댑터가 없어 로그아웃 미수행");
// return;
// }
//
// AdapterPropManager manager = AdapterPropManager.getInstance();
// Properties outboundProp = (Properties)manager.getProperties(avo.getPropGroupName()).clone();
// String charset = outboundProp.getProperty(HttpClientAdapterServiceKey.ENCODE, "utf-8");
//
// if(logger.isDebug())
// logger.debug("logout send >> "+sendData);
//
// byte[] reqBytes = sendData.getBytes(charset);
// Properties tempProp = new Properties();
// tempProp.put(HttpClientAdapterServiceKey.TRAN_CODE, logoutServiceId);
// tempProp.setProperty(HttpClientAdapterServiceKey.ADAPTER_GROUP_NAME, adapterGroupName);
// tempProp.setProperty(HttpClientAdapterServiceKey.ADAPTER_NAME, avo.getName());
//
// byte[] resBytes = null;
// if ("SOCKETOUT".equals(eaiMsg.getCurrentSvcMsg().getOutbRtnNm()) ){
// resBytes = SocketSender.callService(adapterGroupName, outboundProp, reqBytes, tempProp);
// }else{
// resBytes = HttpSender.callService(adapterGroupName, outboundProp, reqBytes, tempProp);
// }
//
// if(logger.isDebug()){
// String recvData = new String(resBytes, charset);
// logger.debug("logout recv << "+recvData);
// }
//
// ExtMessage resExtMessage = ExtMessageConverter.getExtMessageForStandard(resBytes, gvo.getMessageType());
//
// SessionHistoryLogger.getInstance().log(
// new SessionHistoryDTO(sendData, historyDstcd, resExtMessage.getResponseType(), uuid, null, true));
//
// } catch (Exception e) {
//
// SessionHistoryLogger.getInstance().log(
// new SessionHistoryDTO(sendData, historyDstcd, "C", uuid, null, true));
//
// throw e;
// }
}
}
@@ -0,0 +1,334 @@
package com.eactive.eai.common.session;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.ignite.events.CacheEvent;
import org.apache.ignite.events.EventType;
import org.apache.ignite.internal.binary.BinaryObjectImpl;
import org.apache.ignite.lang.IgnitePredicate;
import com.eactive.eai.common.message.EAIMessage;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.session.ChannelSessionFacade.LogoutType;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.worker.Future;
import com.eactive.eai.common.worker.ResponseMap;
public class IgniteEvent implements IgnitePredicate<CacheEvent> {
private static final long serialVersionUID = 1L;
static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
private static final ExecutorService executor = new ThreadPoolExecutor(20, 20, 0, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>());
@Override
public boolean apply(CacheEvent event) {
IgniteEventDataBundle bundle = new IgniteEventDataBundle(event);
if (logger.isDebug()) {
logger.debug("localListener] local event<"+ event.name() +"> [name= " + bundle.getCacheName() + ", " + "key=" + bundle.getKey() + ", "
+ "oldVal=" + bundle.getOldValue() + ", " + "newVal=" + bundle.getNewValue());
}
// if (SessionManager.TOPIC_CAHCE_NAME.equals(bundle.getCacheName()) && EventType.EVT_CACHE_OBJECT_PUT == bundle.getEventType()) {
// removeTopic(bundle);
// }
if (SessionManager.TOPIC_CAHCE_NAME.equals(bundle.getCacheName()) && EventType.EVT_CACHE_OBJECT_PUT == bundle.getEventType()) {
Future future = ResponseMap.getInstance().get(event.key());
if ( future == null) {
if (logger.isDebug()) {
logger.debug("localListener] event.key["+event.key() + "] skip to Future");
}
} else {
if (logger.isDebug()) {
logger.debug("localListener] event.key["+event.key() + "] put to Future");
}
EAIMessage data = (EAIMessage)event.newValue();
future.getSlot().put(data);
}
} else
if (SessionManager.LOGIN_CAHCE_NAME.equals(bundle.getCacheName())
&& EventType.EVT_CACHE_OBJECT_REMOVED == bundle.getEventType()) {
// if (logger.isWarn()) {
// logger.warn("localListener] loginSession removed event[" + bundle.getKey() + "] start");
// }
// if (isWebSocketContainer(bundle)) {
// closeWebSocket(bundle);
// }
} else if (SessionManager.LOGIN_CAHCE_NAME.equals(bundle.getCacheName())
&& EventType.EVT_CACHE_OBJECT_EXPIRED == bundle.getEventType()) {
// if (logger.isWarn()) {
// logger.warn("localListener] loginSession expired event[" + bundle.getKey() + "] start");
// }
// if (isWebSocketContainer_or_httpLoginContainer(bundle)) {
// SessionStatusManager.getInstance().manageLoginStatus(bundle.getKey());
// closeWebSocketWithLogoutTransaction(bundle);
// }
} else if (SessionManager.HTTP_CAHCE_NAME.equals(bundle.getCacheName())
&& EventType.EVT_CACHE_OBJECT_EXPIRED == bundle.getEventType()) {
if (logger.isWarn()) {
logger.warn("localListener] httpLogin expired event[" + bundle.getKey() + "] start");
}
// if (isWebSocketContainer_or_httpLoginContainer(bundle)) {
// removeLoginCacheWithLogoutTransaction(bundle, LogoutType.AutoLogout);
// }
manageLoginStatusWithUUID(bundle);
} else if (SessionManager.WEBSOCKER_CAHCE_NAME.equals(bundle.getCacheName())
&& EventType.EVT_CACHE_OBJECT_EXPIRED == bundle.getEventType()) {
// if (logger.isWarn()) {
// logger.warn("localListener] webSocketTimeout expired event[" + bundle.getKey() + "] start");
// }
// if (isHTTPLoginContainer(bundle)) {
// removeLoginCacheWithLogoutTransaction(bundle, LogoutType.WebSocketTimeout);
// }
}
return true; // Continue listening.
}
private void removeTopic(IgniteEventDataBundle bundle) {
EAIMessage data = (EAIMessage) bundle.getNewValue();
if (logger.isDebug()) {
logger.debug("localListener] setEvent[" + bundle.getKey() + "]");
}
Future future = ResponseMap.getInstance().get(bundle.getKey());
if (future != null) {
if (logger.isDebug()) {
logger.debug("localListener] setEvent[" + bundle.getKey() + "] put to Future");
}
future.getSlot().put(data);
SessionManager.getInstance().removeTopic(bundle.getKey());
}
}
private boolean isWebSocketContainer(IgniteEventDataBundle bundle) {
if (logger.isWarn()) {
logger.warn("localListener] loginSession setExpireEvent[" + bundle.getKey() + "] start");
}
SessionVO sessionVo = bundle.getSessionVO();
if (sessionVo == null) {
if (logger.isWarn()) {
logger.warn("localListener] loginSession setExpireEvent SessionVO not found! - " + bundle.getKey());
}
return false;
}
EAIServerManager eaiServerManager = EAIServerManager.getInstance();
String serverName = eaiServerManager.getLocalServerName();
String webSocketInstanceName = sessionVo.getWsInstId();
if (webSocketInstanceName == null) {
return false;
} else if (serverName.equals(webSocketInstanceName)) {
return true;
}
if (logger.isWarn()) {
logger.warn("localListener] loginSession setExpireEvent[" + bundle.getKey() + "] skip.. ");
}
return false;
}
private boolean isWebSocketContainer_or_httpLoginContainer(IgniteEventDataBundle bundle) {
if (logger.isWarn()) {
logger.warn("localListener] loginSession event[" + bundle.getKey() + "] start");
}
SessionVO sessionVo = bundle.getSessionVO();
if (sessionVo == null) {
if (logger.isWarn()) {
logger.warn("localListener] loginSession event SessionVO not found! - " + bundle.getKey());
}
return false;
}
EAIServerManager eaiServerManager = EAIServerManager.getInstance();
String serverName = eaiServerManager.getLocalServerName();
String webSocketInstanceName = sessionVo.getWsInstId();
if (webSocketInstanceName == null) {
if (serverName.equals(sessionVo.getLoginInstId())) {
return true;
}
} else if (serverName.equals(webSocketInstanceName)) {
return true;
}
if (logger.isWarn()) {
logger.warn("localListener] loginSession event[" + bundle.getKey() + "] skip.. ");
}
return false;
}
private boolean isHTTPLoginContainer(IgniteEventDataBundle bundle) {
SessionVO sessionVo = bundle.getSessionVO();
if (sessionVo == null) {
if (logger.isWarn()) {
logger.warn("localListener] loginSession setExpireEvent SessionVO not found! - " + bundle.getKey());
}
return false;
}
String localServerName = EAIServerManager.getInstance().getLocalServerName();
String httpLoginInstanceName = sessionVo.getLoginInstId();
if (localServerName.equals(httpLoginInstanceName)) {
return true;
} else {
if (logger.isWarn()) {
logger.warn("localListener] loginSession setExpireEvent[" + bundle.getKey() + "] skip.. ");
}
return false;
}
}
private void closeWebSocket(IgniteEventDataBundle bundle) {
if (logger.isWarn()) {
logger.warn("localListener] loginSession closeWebSocket[" + bundle.getKey() + "] start");
}
SessionVO sessionVo = bundle.getSessionVO();
String adapterGroupName = sessionVo.getWsAdapterGroupName();
try {
executor.execute(() -> {
ChannelSessionFacade.getInstance().closeWebSocketByAdapterGroupAndUserId(adapterGroupName,
bundle.getKey(), false, LogoutType.AutoLogout);
});
if (logger.isDebug()) {
logger.debug("localListener] loginSession ChannelSessionFacade.closeWebSocketByAdapterGroupAndUserId ["
+ bundle.getKey() + "] -" + adapterGroupName);
}
} catch (Exception ex) {
logger.error(
"localListener] loginSession login removed ChannelSessionFacade.closeWebSocketByAdapterGroupAndUserId failed, adapterGroupName ["
+ adapterGroupName + "] loginUserId [" + bundle.getKey() + "]",
ex);
}
if (logger.isWarn()) {
logger.warn("localListener] loginSession login removed[" + bundle.getKey() + "] end");
}
}
private void closeWebSocketWithLogoutTransaction(IgniteEventDataBundle bundle) {
if (logger.isWarn()) {
logger.warn(
"localListener] loginSession closeWebSocketWithLogoutTransaction[" + bundle.getKey() + "] start");
}
SessionVO sessionVo = bundle.getSessionVO();
String adapterGroupName = sessionVo.getWsAdapterGroupName();
try {
executor.execute(() -> {
ChannelSessionFacade.getInstance().closeWebSocketByAdapterGroupAndUserId(adapterGroupName,
bundle.getKey(), true, LogoutType.AutoLogout);
ChannelSessionFacade.getInstance().removeFromHttpCacheByUserId(bundle.getKey());
});
if (logger.isDebug()) {
logger.debug("localListener] loginSession ChannelSessionFacade.closeWebSocketByAdapterGroupAndUserId ["
+ bundle.getKey() + "] - adapterGroupName : " + adapterGroupName);
}
} catch (Exception ex) {
logger.error(
"localListener] loginSession login expired ChannelSessionFacade.closeWebSocketByAdapterGroupAndUserId failed, adapterGroupName ["
+ adapterGroupName + "] loginUserId [" + bundle.getKey() + "]",
ex);
}
if (logger.isWarn()) {
logger.warn("localListener] loginSession login expired[" + bundle.getKey() + "] end. ");
}
}
private void removeLoginCacheWithLogoutTransaction(IgniteEventDataBundle bundle, LogoutType logoutType) {
if (logger.isWarn()) {
logger.warn("localListener] loginSession removeLoginCacheWithLogoutTransaction [" + bundle.getKey()
+ "] start");
}
SessionVO sessionVo = bundle.getSessionVO();
try {
executor.execute(() -> {
ChannelSessionFacade.getInstance().logout(sessionVo.getLoginUserId(), sessionVo.getUuid(), true,
logoutType);
});
if (logger.isDebug()) {
logger.debug("localListener] loginSession ChannelSessionFacade.logout [" + bundle.getKey() + "]");
}
} catch (Exception e) {
logger.error("localListener] loginSession HTTP expired ChannelSessionFacade.logout failed", e);
}
if (logger.isWarn()) {
logger.warn("localListener] loginSession HTTP expired [" + bundle.getKey() + "] end. ");
}
}
private void manageLoginStatusWithUUID(IgniteEventDataBundle bundle) {
if (logger.isWarn()) {
logger.warn("localListener] loginSession manageLoginStatusWithUUID [" + bundle.getKey() + "] start");
}
SessionVO sessionVo = bundle.getSessionVO();
SessionStatusManager.getInstance().manageLoginStatusWithUUID(sessionVo);
}
public void shutdown() {
if(executor != null) {
executor.shutdown();
}
}
}
class IgniteEventDataBundle {
private String cacheName;
private int eventType;
private String key;
private Object oldValue;
private Object newValue;
private SessionVO sessionVO;
public IgniteEventDataBundle(CacheEvent event) {
cacheName = event.cacheName();
eventType = event.type();
key = event.key();
oldValue = event.oldValue();
newValue = event.newValue();
if (oldValue instanceof SessionVO) {
sessionVO = (SessionVO) oldValue;
}
else if (oldValue instanceof BinaryObjectImpl) {
BinaryObjectImpl b = (BinaryObjectImpl) oldValue;
sessionVO = (SessionVO) b.deserialize();
}
}
public String getCacheName() {
return cacheName;
}
public int getEventType() {
return eventType;
}
public String getKey() {
return key;
}
public Object getOldValue() {
return oldValue;
}
public Object getNewValue() {
return newValue;
}
public SessionVO getSessionVO() {
return sessionVO;
}
}
@@ -0,0 +1,63 @@
package com.eactive.eai.common.session;
import com.eactive.eai.common.util.Logger;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import net.sf.ehcache.event.CacheEventListener;
import net.sf.ehcache.event.CacheEventListenerFactory;
import java.util.Properties;
public class LoggingCacheListenerFactory extends CacheEventListenerFactory {
static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
@Override
public CacheEventListener createCacheEventListener(Properties properties) {
return new CacheEventListener(){
public Object clone() throws CloneNotSupportedException{
logger.debug("LoggingCacheListenerFactory] Clone obtained");
return super.clone();
}
@Override
public void dispose() {
logger.debug("LoggingCacheListenerFactory] disponse the listener");
}
@Override
public void notifyElementEvicted(Ehcache ehcache,
Element element) {
logger.debug("LoggingCacheListenerFactory] Element evicted from the cache: "+element.getObjectKey());
}
@Override
public void notifyElementExpired(Ehcache ehcache,
Element element) {
logger.debug("LoggingCacheListenerFactory] Element expired in the cache: "+element.getObjectKey());
}
@Override
public void notifyElementPut(Ehcache ehcache, Element element)
throws CacheException {
logger.debug("LoggingCacheListenerFactory] Element put into the cache: "+element.getObjectKey());
}
@Override
public void notifyElementRemoved(Ehcache ehcache,
Element element) throws CacheException {
logger.debug("LoggingCacheListenerFactory] Element remove from the cache: "+element.getObjectKey());
}
@Override
public void notifyElementUpdated(Ehcache ehcache,
Element element) throws CacheException {
logger.debug("LoggingCacheListenerFactory] Element updated in the cache: "+element.getObjectKey());
}
@Override
public void notifyRemoveAll(Ehcache ehcache) {
logger.debug("LoggingCacheListenerFactory] Element remove all element from the cache");
}
};
}
}
@@ -0,0 +1,44 @@
package com.eactive.eai.common.session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.eactive.eai.common.dao.DAOException;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.property.PropertyLoginKeys;
import com.eactive.eai.common.sessioninfo.SessionHistoryDAO;
import com.eactive.eai.common.sessioninfo.SessionHistoryDTO;
import com.eactive.eai.common.util.ApplicationContextProvider;
import com.eactive.eai.common.util.Logger;
@Component("onlSessionHistoryLogger")
public class SessionHistoryLogger {
static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);
@Autowired
private SessionHistoryDAO sessionHistoryDAO;
// private static SessionHistoryLogger instance = null;
private SessionHistoryLogger() {
}
public static SessionHistoryLogger getInstance() {
return ApplicationContextProvider.getContext().getBean(SessionHistoryLogger.class);
}
public void log(SessionHistoryDTO sessionHistoryDTO) {
try {
if (!"Y".equals(PropManager.getInstance().getProperty(PropertyLoginKeys.LOGIN,
PropertyLoginKeys.LOGIN_LOGGING_YN, "Y"))) {
logger.debug("LOGIN_LOGGING_YN option is \"N\". SessionHistory not logged.");
return;
}
sessionHistoryDAO.insertSessionHistory(sessionHistoryDTO.toVo());
} catch (DAOException de) {
logger.error("SessionHistoryLogger] Fail logging session history. sessionHistoryDTO : "
+ sessionHistoryDTO.toString(), de);
}
}
}
@@ -0,0 +1,237 @@
package com.eactive.eai.common.session;
import com.eactive.eai.common.lifecycle.Lifecycle;
import com.eactive.eai.common.lifecycle.LifecycleException;
import com.eactive.eai.common.lifecycle.LifecycleListener;
import com.eactive.eai.common.lifecycle.LifecycleSupport;
import com.eactive.eai.common.message.EAIMessage;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.server.EAIServerVO;
import com.eactive.eai.common.sessioninfo.TerminalInfoVO;
import com.eactive.eai.common.util.Logger;
/**
* 1. 기능 :
* 1) websocket login session 정보
* 2) SA 응답거래 매핑 정보
* 3) Single Socket 접속정보
* 4) 복원거래에 대한 헤더정보 저장
* 정보 공유 관리하는 Manager 클래스
* 2. 처리 개요 : Cache 를 통한 기능처리
* 3. 주의사항
* 4. 오류처리
* deadlock 회피 - 2022.01.05 jun's
* 1. WebSocketSessionManager.sessionClose() : synchronized 범위변경
* 2. CustomRMICacheEventListener
* - cache 가 다른 cache에 접근할때 Thread 방식으로 변경
* - websocket 인스턴스에서만 작동하도록변경
* 인스턴스 stop시 오류
* 1. WebSocket 인증시에 HttpLogin 의 websocket instance및 어댑터 그룹 갱신
* 2. sessionManager stop 시 expireThread interrupt 후 logout 처리 및 cacheManager.shutdown
*
*
* @author :
* @version : v 1.0.0
* @see : 관련 기능을 참조
* @since :
* :
*/
public abstract class SessionManager implements Lifecycle {
static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
public static final String ADAPTER_MASTER_CAHCE_NAME = "evictMasterCache";
public static final String ADAPTER_CAHCE_NAME = "adapterSession";
public static final String TOPIC_CAHCE_NAME = "topic";
public static final String TOPIC_MAXSZIE = "topicMaxSize";
public static final String CACHE_TOPIC_DURATION = "topicDurationSecs";
public static final String CACHE_WORKING_DIR= "workingDir";
public static final String STORE_CAHCE_NAME = "cacheStore";
public static final String CAHCE_STORE_MAXSIZE = "cacheStoreMaxSize";
public static final String CACHE_STORE_DURATION = "cacheStoreDurationSecs";
// public static final String CACHE_MAX_MEM_MB = "cacheMaxMemMb";
public static final String LOGIN_CAHCE_NAME = "loginSession";
public static final String HTTP_CAHCE_NAME = "httpLogin";
public static final String USERID_CAHCE_NAME = "convertUserIdSession";
public static final String WEBSOCKER_CAHCE_NAME = "webSocketTimeout";
public static final String TERMINAL_CAHCE_NAME = "terminalSession";
public static final String SESSION_MANAGER_GROUPNAME = "RMIInfo";
public static final String SESSION_MANAGER_CACHETYPE = "cacheType";
public static final String SESSION_MANAGER_CACHETYPE_IGNITE = "IGNITE";
public static final String SESSION_MANAGER_CACHETYPE_EHCACHE = "EHCACHE";
public static final String SESSION_MANAGER_EXPIRE_INTERVAL = "expireInterval";
public static final String SESSION_MANAGER_MULTI_GROUP_IP = "multi_group_ip";
public static final String SESSION_MANAGER_MULTI_GROUP_PORT = "multi_group_port";
public static final String SESSION_MANAGER_SESSION_TIMEOUT = "sessionTimeout";
public static final String SESSION_MANAGER_WEBSOCKET_TIMEOUT = "webSocketTimeout";
public static final String SESSION_MANAGER_KUBERNETES_NAMESPACE = "kubernetes_namespace";
public static final String SESSION_MANAGER_KUBERNETES_SERVICENAME = "kubernetes_servicename";
public static final String SESSION_MANAGER_KUBERNETES_MASTERURL = "kubernetes_masterurl";
public static final String SESSION_MANAGER_KUBERNETES_ACCOUNTTOKEN = "kubernetes_accounttoken";
public static final String SESSION_MANAGER_KUBERNETES_DISCOVERYPORT = "kubernetes_discoveryport";
public static final String ENABLE_MULTILOGIN_YN = "enable_multilogin_yn";
public static final String SESSION_VO_VALIDATION_FROM = "session_vo_validation_from";
private static ChannelSessionFacade channelSessionFacade;
private static SessionManager instance;
private boolean started;
public static final String MASTER_KEY = "master";
private LifecycleSupport lifecycle = new LifecycleSupport(this);
protected SessionManager() {
// nothing to do
}
public static synchronized SessionManager getInstance() {
if (instance == null) {
PropManager manager = PropManager.getInstance();
String type = manager.getProperty(SessionManager.SESSION_MANAGER_GROUPNAME,
SessionManager.SESSION_MANAGER_CACHETYPE, SESSION_MANAGER_CACHETYPE_IGNITE);
if (SESSION_MANAGER_CACHETYPE_IGNITE.equalsIgnoreCase(type)) {
instance = new SessionManagerForIgnite();
} else if (SESSION_MANAGER_CACHETYPE_EHCACHE.equalsIgnoreCase(type)) {
instance = new SessionManagerForEhcache();
} else {
instance = new SessionManagerForIgnite();
}
}
return instance;
}
public void start() throws LifecycleException {
if (started) {
throw new LifecycleException("RECEAICRT201");
}
lifecycle.fireLifecycleEvent(STARTING_EVENT, this);
int port = 0;
int remoteObjectPort = 0;
channelSessionFacade = ChannelSessionFacade.getInstance();
EAIServerManager mgr = EAIServerManager.getInstance();
EAIServerVO vo = mgr.getEAIServer(mgr.getLocalServerName());
// site의 포트 정책에 따라 변경될 수 있음.
// EAIServerVO 에 정의됨.
port = vo.getCacheLocalPort();
remoteObjectPort = vo.getCacheRemotePort();
init(port, remoteObjectPort);
started = true;
lifecycle.fireLifecycleEvent(STARTED_EVENT, this);
}
public void stop() throws LifecycleException {
if (!started) {
throw new LifecycleException("RECEAICRT203");
}
lifecycle.fireLifecycleEvent(STOPING_EVENT, this);
channelSessionFacade.onServerDown();
started = false;
lifecycle.fireLifecycleEvent(STOPPED_EVENT, this);
}
public void addLifecycleListener(LifecycleListener listener) {
lifecycle.addLifecycleListener(listener);
}
public LifecycleListener[] findLifecycleListeners() {
return lifecycle.findLifecycleListeners();
}
public void removeLifecycleListener(LifecycleListener listener) {
lifecycle.removeLifecycleListener(listener);
}
public boolean isStarted() {
return this.started;
}
protected abstract void init(int localPort, int remoteObjectPort);
// Single Socket 관련
public abstract SessionVO getConnectionInfo(String key);
public abstract SessionVO getConnectionStatus(String key);
public abstract void putConnectionInfo(String key, SessionVO value);
public abstract void removeConnectionInfo(String key);
// Topic 관련
public abstract EAIMessage getTopic(String key);
public abstract void putTopic(String key, EAIMessage value);
public abstract void removeTopic(String key);
// 비동기 거래 복원용
public abstract String getCacheStore(String key);
public abstract void putCacheStore(String key, String value, int ttlSecs);
public abstract void putCacheStore(String key, String value);
public abstract void removeCacheStore(String key);
// Login Cache
public abstract SessionVO getLogin(String key);
public abstract void putLogin(String key, SessionVO value);
public abstract void removeLogin(String key);
// HTTP Cache
public abstract SessionVO getHttpLogin(String key);
public abstract void putHttpLogin(String key, SessionVO value);
public abstract void removeHTTPLogin(String key);
// Terminal
public abstract TerminalVO getTerminal(String key);
public abstract void putTerminal(String key, TerminalVO value, TerminalInfoVO terminalInfoVO);
public abstract void removeTerminal(String key);
// CacheInfoVO
public abstract CacheInfoVO getLoginCache();
public abstract CacheInfoVO getHttpLoginCache();
public abstract CacheInfoVO getEvictMasterCache();
public abstract CacheInfoVO getTerminalCache();
public abstract CacheInfoVO getConvertUserIdCache();
public abstract CacheInfoVO getSocketCache();
public abstract String getMasterInstId();
// Convert terminalId to userId
public abstract String getConvertUserId(String key);
// WebSocketTimeout Cache
public abstract void putWebSocketTimeout(String key, SessionVO value);
public abstract void removeWebSocketTimeout(String key);
public abstract void closeManager();
public abstract String getCacheStatus();
}
@@ -0,0 +1,924 @@
package com.eactive.eai.common.session;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import com.eactive.eai.common.ehcache.CustomRMICacheReplicatorFactory;
import com.eactive.eai.common.logger.EAIDBLogControl;
import com.eactive.eai.common.message.EAIMessage;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.sessioninfo.SessionInfoVO;
import com.eactive.eai.common.sessioninfo.TerminalInfoDAO;
import com.eactive.eai.common.sessioninfo.TerminalInfoVO;
import com.eactive.eai.common.util.ApplicationContextProvider;
import com.eactive.eai.util.HealthCheckManager;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import net.sf.ehcache.bootstrap.BootstrapCacheLoader;
import net.sf.ehcache.bootstrap.BootstrapCacheLoaderFactory;
import net.sf.ehcache.config.CacheConfiguration;
import net.sf.ehcache.config.Configuration;
import net.sf.ehcache.config.FactoryConfiguration;
import net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory;
import net.sf.ehcache.distribution.RMICacheReplicatorFactory;
import net.sf.ehcache.event.CacheEventListener;
import net.sf.ehcache.event.CacheEventListenerFactory;
//use Ehcache
public class SessionManagerForEhcache extends SessionManager {
// evictMaster Instance - single socket 관련
private static Cache evictMasterCache = null;
// Socket Session cache 정보
private static Cache cacheSocket = null;
// Topic 용 cache 정보
private static Cache cacheTopic = null;
// 비동기 거래 복원용
private static Cache cacheStore = null;
// WebSocket Login cache 정보
private static Cache cacheLogin = null; // key = loginId
private static Cache cacheConvertUserId = null; // 단말ID 를 userID로 변경
// HTTP Polling 에 대한 timeout 관리용
private static Cache httpLogin = null; // key == uuid
// Terminal용 cache 정보 : ATM, 무인공과금
private static Cache cacheTerminal = null;
// HTTP Login 후 WebSocket Connection 일정 시간동안 없을시 Expired되며 자동 로그아웃 발생
private static Cache cacheWebSocketTimeout = null;
private static CacheManager manager = null;
// expireThread run interval secs, default 10 secs
int expireInterval = 10;
Thread expireThread = null;
String localServerName = null;
private int cacheStoreDurationSecs = 60;
private final String logPrefix = this.getClass().getName();
public void init(int localPort, int remoteObjectPort) {
PropManager pManager = PropManager.getInstance();
Properties prpty = pManager.getProperties(SessionManager.SESSION_MANAGER_GROUPNAME);
String mltIp = "230.0.0.1"; // 224.0.1.0 ~ 239.255.255.255
String gPort = "4443";
int sessionTimeout = 60;
int webSocketTimeout = 60;
int topicTimeout = 60;
int topicMaxSize = 10000;
int cacheStoreMaxSize = 10000;
EAIServerManager eaiServerManager = EAIServerManager.getInstance();
localServerName = eaiServerManager.getLocalServerName();
if (prpty != null) {
mltIp = prpty.getProperty(SessionManager.SESSION_MANAGER_MULTI_GROUP_IP);
gPort = prpty.getProperty(SessionManager.SESSION_MANAGER_MULTI_GROUP_PORT);
String sTimeout = prpty.getProperty(SessionManager.SESSION_MANAGER_SESSION_TIMEOUT);
if (sTimeout != null) {
try {
sessionTimeout = Integer.parseInt(sTimeout);
if (sessionTimeout < 30)
sessionTimeout = 30;
} catch (NumberFormatException ex) {
sessionTimeout = 60;
}
}
String sExpireInterval = prpty.getProperty(SessionManager.SESSION_MANAGER_EXPIRE_INTERVAL);
if (sExpireInterval != null) {
try {
expireInterval = Integer.parseInt(sExpireInterval);
if (expireInterval < 10)
expireInterval = 10;
} catch (NumberFormatException ex) {
expireInterval = 10;
}
}
String wTimeout = prpty.getProperty(SessionManager.SESSION_MANAGER_WEBSOCKET_TIMEOUT);
if (wTimeout != null) {
try {
webSocketTimeout = Integer.parseInt(wTimeout);
} catch (NumberFormatException ex) {
webSocketTimeout = 60;
}
}
String topicTimeoutSec = prpty.getProperty(SessionManager.CACHE_TOPIC_DURATION);
if (topicTimeoutSec != null) {
try {
topicTimeout = Integer.parseInt(topicTimeoutSec);
if (topicTimeout < 0)
topicTimeout = 60;
} catch (NumberFormatException ex) {
topicTimeout = 60;
}
}
String topicMax = prpty.getProperty(SessionManager.TOPIC_MAXSZIE);
if (topicMax != null) {
try {
topicMaxSize = Integer.parseInt(topicMax);
if (topicMaxSize < 0)
topicMaxSize = 10000;
} catch (NumberFormatException ex) {
topicMaxSize = 10000;
}
}
String durationSecs = prpty.getProperty(SessionManager.CACHE_STORE_DURATION);
if (durationSecs != null) {
try {
cacheStoreDurationSecs = Integer.parseInt(durationSecs);
if (cacheStoreDurationSecs < 60)
cacheStoreDurationSecs = 60;
} catch (NumberFormatException ex) {
cacheStoreDurationSecs = 60;
}
}
String cacheStoreMax = prpty.getProperty(SessionManager.CAHCE_STORE_MAXSIZE);
if (cacheStoreMax != null) {
try {
cacheStoreMaxSize = Integer.parseInt(cacheStoreMax);
if (cacheStoreMaxSize < 0)
cacheStoreMaxSize = 10000;
} catch (NumberFormatException ex) {
cacheStoreMaxSize = 10000;
}
}
}
System.setProperty("net.sf.ehcache.skipUpdateCheck", "true");
String bootstrapAsynchronously = "false";
Configuration cf = new Configuration();
FactoryConfiguration ppFactory = new FactoryConfiguration();
/**
* manual로 설정할경우 shutdown시 멈춤현상이 발생 auto로 변경됨
* ppFactory.setClass("com.eactive.eai.common.session.TimeoutRMICacheManagerPeerProviderFactory");
* ppFactory.setProperties("peerDiscovery=manual,rmiUrls="+rmiUrls);
*/
ppFactory.setClass("net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory");
ppFactory.setProperties(
"peerDiscovery=automatic,multicastGroupAddress=" + mltIp + ", multicastGroupPort=" + gPort);
ppFactory.setPropertySeparator(",");
cf.addCacheManagerPeerProviderFactory(ppFactory);
logger.debug(logPrefix + " >>>>INIT<<< Multicast ip = " + mltIp + ", port = " + gPort);
FactoryConfiguration plFactory = new FactoryConfiguration();
plFactory.setClass("net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory");
plFactory.setProperties("port=" + localPort + ", remoteObjectPort=" + remoteObjectPort);
plFactory.setPropertySeparator(",");
cf.addCacheManagerPeerListenerFactory(plFactory);
CacheConfiguration defaultCacheConfiguration = new CacheConfiguration();
defaultCacheConfiguration.setName("ChannelSessionCache");
defaultCacheConfiguration.setMaxElementsInMemory(200000);
cf.addDefaultCache(defaultCacheConfiguration);
manager = new CacheManager(cf);
initSocket(manager, sessionTimeout, 10000, bootstrapAsynchronously);
initTopic(manager, topicTimeout, topicMaxSize, bootstrapAsynchronously);
initCacheStore(manager, cacheStoreDurationSecs, cacheStoreMaxSize, bootstrapAsynchronously);
initLogin(manager, sessionTimeout, 20000, bootstrapAsynchronously);
initHttpLogin(manager, sessionTimeout, 20000, bootstrapAsynchronously);
initEvict(manager, sessionTimeout, 10, bootstrapAsynchronously);
initTerminal(manager, sessionTimeout, 20000, bootstrapAsynchronously);
initConvertUserId(manager, sessionTimeout, 20000, bootstrapAsynchronously);
initWebSocketTimeout(manager, webSocketTimeout, 20000, bootstrapAsynchronously);
/**
* expire event가 전파가 안되는 문제 발견(2022-01-13)
* 조치는 master에서만 하는게 아니라 전체 인스턴스에서
* expireThread 실행되도록변경
*/
expireThread = new Thread() {
@Override
public void run() {
String logPrefix = "SessionManager.expireThread] ";
while (true) {
String master = null;
try {
Thread.sleep(expireInterval * 1000);
if (evictMasterCache.getSize() > 0) {
evictMasterCache.evictExpiredElements();
Element element = evictMasterCache.get(MASTER_KEY);
if (element == null) {
evictMasterCache.put(new Element(MASTER_KEY, localServerName));
if (logger.isInfo())
logger.info(logPrefix + "EVICT-PUT master = " + localServerName);
} else {
master = (String) element.getObjectValue();
if (localServerName.equals(master)) {
evictMasterCache.put(new Element(MASTER_KEY, localServerName));
}
}
} else {
evictMasterCache.put(new Element(MASTER_KEY, localServerName));
if (logger.isInfo())
logger.info(logPrefix + "INIT-PUT master = " + localServerName);
}
int cacheSize = cacheLogin.getSize();
if (cacheSize > 0) {
if (logger.isInfo()) {
logger.info(logPrefix + "cacheLogin.evictExpiredElements = " + cacheSize);
}
cacheLogin.evictExpiredElements();
}
cacheSize = httpLogin.getSize();
if (cacheSize > 0) {
if (logger.isInfo()) {
logger.info(logPrefix + "httpLogin.evictExpiredElements = " + cacheSize);
}
httpLogin.evictExpiredElements();
}
} catch (InterruptedException ie) {
logger.error(logPrefix + "expireThread error - stop", ie);
break;
} catch (Exception e) {
logger.error(logPrefix + "expireThread error - skip", e);
}
}
}
};
expireThread.setName("SessionManagerForEhcache-expireThread");
expireThread.start();
}
private synchronized void initEvict(CacheManager manager, int sessionTimeout, int maxSize, String bootstrapAsynchronously) {
int masterTimeout = (expireInterval + expireInterval / 2);
if (logger.isDebug()) {
logger.debug(logPrefix + " create evictMasterCache cache - expire=" + masterTimeout + ", maxSize=" + maxSize);
}
evictMasterCache = new Cache(ADAPTER_MASTER_CAHCE_NAME, 10, false, false, masterTimeout, masterTimeout);
CacheEventListenerFactory celf = new RMICacheReplicatorFactory();
Properties celfProp = new Properties();
celfProp.put("replicateAsynchronously", "false");
celfProp.put("asynchronousReplicationIntervalMillis", "1000");
CacheEventListener cel = celf.createCacheEventListener(celfProp);
evictMasterCache.getCacheEventNotificationService().registerListener(cel);
@SuppressWarnings("rawtypes")
BootstrapCacheLoaderFactory bclf = new RMIBootstrapCacheLoaderFactory();
Properties bclfProp = new Properties();
bclfProp.put("bootstrapAsynchronously", bootstrapAsynchronously);
bclfProp.put("maximumChunkSizeBytes", "5000000");
BootstrapCacheLoader bcl = bclf.createBootstrapCacheLoader(bclfProp);
evictMasterCache.setBootstrapCacheLoader(bcl);
manager.addCache(evictMasterCache);
}
private synchronized void initSocket(CacheManager manager, int sessionTimeout, int maxSize, String bootstrapAsynchronously) {
if (logger.isDebug()) {
logger.debug(logPrefix + " create AdapterSession cache sessionTimeout="+sessionTimeout +", maxSize=" + maxSize);
}
cacheSocket = new Cache(ADAPTER_CAHCE_NAME, maxSize, false, false, 0, 0);
CacheEventListenerFactory celf = new RMICacheReplicatorFactory();
Properties celfProp = new Properties();
celfProp.put("replicateAsynchronously", "false");
// celfProp.put("asynchronousReplicationIntervalMillis", "100");
CacheEventListener cel = celf.createCacheEventListener(celfProp);
cacheSocket.getCacheEventNotificationService().registerListener(cel);
@SuppressWarnings("rawtypes")
BootstrapCacheLoaderFactory bclf = new RMIBootstrapCacheLoaderFactory();
Properties bclfProp = new Properties();
bclfProp.put("bootstrapAsynchronously", bootstrapAsynchronously);
bclfProp.put("maximumChunkSizeBytes", "5000000");
BootstrapCacheLoader bcl = bclf.createBootstrapCacheLoader(bclfProp);
cacheSocket.setBootstrapCacheLoader(bcl);
manager.addCache(cacheSocket);
}
private synchronized void initTopic(CacheManager manager, int sessionTimeout, int maxSize, String bootstrapAsynchronously) {
if (logger.isDebug()) {
logger.debug(logPrefix + " create topic cache sessionTimeout="+sessionTimeout +", maxSize=" + maxSize);
}
cacheTopic = new Cache(TOPIC_CAHCE_NAME, maxSize, false, false, sessionTimeout, sessionTimeout);
CacheEventListenerFactory celf = new RMICacheReplicatorFactory();
Properties celfProp = new Properties();
celfProp.put("replicateAsynchronously", "false");
celfProp.put("asynchronousReplicationIntervalMillis", "1000");
CacheEventListener cel = celf.createCacheEventListener(celfProp);
cacheTopic.getCacheEventNotificationService().registerListener(cel);
// add Custom EventListener
CacheEventListenerFactory ccelf = new CustomRMICacheReplicatorFactory();
Properties ccelfProp = new Properties();
ccelfProp.put("replicateAsynchronously", "false");
ccelfProp.put("asynchronousReplicationIntervalMillis", "1000");
CacheEventListener ccel = ccelf.createCacheEventListener(ccelfProp);
cacheTopic.getCacheEventNotificationService().registerListener(ccel);
@SuppressWarnings("rawtypes")
BootstrapCacheLoaderFactory bclf = new RMIBootstrapCacheLoaderFactory();
Properties bclfProp = new Properties();
bclfProp.put("bootstrapAsynchronously", bootstrapAsynchronously);
bclfProp.put("maximumChunkSizeBytes", "5000000");
BootstrapCacheLoader bcl = bclf.createBootstrapCacheLoader(bclfProp);
cacheTopic.setBootstrapCacheLoader(bcl);
manager.addCache(cacheTopic);
}
private synchronized void initCacheStore(CacheManager manager, int sessionTimeout, int maxSize, String bootstrapAsynchronously) {
if (logger.isDebug()) {
logger.debug(logPrefix + " create cacheStore cache sessionTimeout="+sessionTimeout +", maxSize=" + maxSize);
}
cacheStore = new Cache(STORE_CAHCE_NAME, maxSize, false, false, sessionTimeout, sessionTimeout);
CacheEventListenerFactory celf = new RMICacheReplicatorFactory();
Properties celfProp = new Properties();
celfProp.put("replicateAsynchronously", "false");
celfProp.put("asynchronousReplicationIntervalMillis", "1000");
CacheEventListener cel = celf.createCacheEventListener(celfProp);
cacheStore.getCacheEventNotificationService().registerListener(cel);
// add Custom EventListener
CacheEventListenerFactory ccelf = new CustomRMICacheReplicatorFactory();
Properties ccelfProp = new Properties();
ccelfProp.put("replicateAsynchronously", "false");
ccelfProp.put("asynchronousReplicationIntervalMillis", "1000");
CacheEventListener ccel = ccelf.createCacheEventListener(ccelfProp);
cacheStore.getCacheEventNotificationService().registerListener(ccel);
@SuppressWarnings("rawtypes")
BootstrapCacheLoaderFactory bclf = new RMIBootstrapCacheLoaderFactory();
Properties bclfProp = new Properties();
bclfProp.put("bootstrapAsynchronously", bootstrapAsynchronously);
bclfProp.put("maximumChunkSizeBytes", "5000000");
BootstrapCacheLoader bcl = bclf.createBootstrapCacheLoader(bclfProp);
cacheStore.setBootstrapCacheLoader(bcl);
manager.addCache(cacheStore);
}
private synchronized void initLogin(CacheManager manager, int sessionTimeout, int maxSize, String bootstrapAsynchronously) {
if (logger.isDebug()) {
logger.debug(logPrefix + " create loginSession cache sessionTimeout="+sessionTimeout +", maxSize=" + maxSize);
}
cacheLogin = new Cache(LOGIN_CAHCE_NAME, 20000, false, false, sessionTimeout, sessionTimeout);
String isAsync = PropManager.getInstance().getProperty("LOGIN", "IS_ASYNC", "false");
CacheEventListenerFactory celf = new RMICacheReplicatorFactory();
Properties celfProp = new Properties();
celfProp.put("replicateAsynchronously", isAsync);
// 비동기 방식을 사용할때 변경 내역을 다른 노드에 통지하는 주기 default 1000
celfProp.put("asynchronousReplicationIntervalMillis", "1000");
CacheEventListener cel = celf.createCacheEventListener(celfProp);
cacheLogin.getCacheEventNotificationService().registerListener(cel);
// add Custom EventListener
CacheEventListenerFactory ccelf = new CustomRMICacheReplicatorFactory();
Properties ccelfProp = new Properties();
ccelfProp.put("replicateAsynchronously", isAsync);
ccelfProp.put("asynchronousReplicationIntervalMillis", "1000");
CacheEventListener ccel = ccelf.createCacheEventListener(ccelfProp);
cacheLogin.getCacheEventNotificationService().registerListener(ccel);
@SuppressWarnings("rawtypes")
BootstrapCacheLoaderFactory bclf = new RMIBootstrapCacheLoaderFactory();
Properties bclfProp = new Properties();
bclfProp.put("bootstrapAsynchronously", bootstrapAsynchronously);
bclfProp.put("maximumChunkSizeBytes", "5000000");
BootstrapCacheLoader bcl = bclf.createBootstrapCacheLoader(bclfProp);
cacheLogin.setBootstrapCacheLoader(bcl);
// cacheLogin.getCacheConfiguration().setDiskExpiryThreadIntervalSeconds(10);
manager.addCache(cacheLogin);
logger.warn(logPrefix + " cacheLogin DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS = "
+ Cache.DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS);
}
private synchronized void initHttpLogin(CacheManager manager, int sessionTimeout, int maxSize, String bootstrapAsynchronously) {
if (logger.isDebug()) {
logger.debug(logPrefix + " create httpLogin cache timeToIdleSeconds=" + sessionTimeout);
}
httpLogin = new Cache(HTTP_CAHCE_NAME, 20000, false, false, sessionTimeout, sessionTimeout);
String isAsync = PropManager.getInstance().getProperty("LOGIN", "IS_ASYNC", "false");
CacheEventListenerFactory celf = new RMICacheReplicatorFactory();
Properties celfProp = new Properties();
celfProp.put("replicateAsynchronously", isAsync);
celfProp.put("asynchronousReplicationIntervalMillis", "1000");
CacheEventListener cel = celf.createCacheEventListener(celfProp);
httpLogin.getCacheEventNotificationService().registerListener(cel);
// add Custom EventListener
CacheEventListenerFactory ccelf = new CustomRMICacheReplicatorFactory();
Properties ccelfProp = new Properties();
ccelfProp.put("replicateAsynchronously", isAsync);
ccelfProp.put("asynchronousReplicationIntervalMillis", "1000");
CacheEventListener ccel = ccelf.createCacheEventListener(ccelfProp);
httpLogin.getCacheEventNotificationService().registerListener(ccel);
@SuppressWarnings("rawtypes")
BootstrapCacheLoaderFactory bclf = new RMIBootstrapCacheLoaderFactory();
Properties bclfProp = new Properties();
bclfProp.put("bootstrapAsynchronously", bootstrapAsynchronously);
bclfProp.put("maximumChunkSizeBytes", "5000000");
BootstrapCacheLoader bcl = bclf.createBootstrapCacheLoader(bclfProp);
httpLogin.setBootstrapCacheLoader(bcl);
manager.addCache(httpLogin);
if (logger.isWarn()) {
logger.warn(logPrefix + " httpLogin DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS = "
+ Cache.DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS);
}
}
private synchronized void initConvertUserId(CacheManager manager, int sessionTimeout, int maxSize, String bootstrapAsynchronously) {
if (logger.isDebug()) {
logger.debug(logPrefix + " create convertUserIdSession cache sessionTimeout="+sessionTimeout +", maxSize=" + maxSize);
}
cacheConvertUserId = new Cache(USERID_CAHCE_NAME, maxSize, false, false, sessionTimeout, sessionTimeout);
String isAsync = PropManager.getInstance().getProperty("LOGIN", "IS_ASYNC", "false");
CacheEventListenerFactory celf = new RMICacheReplicatorFactory();
Properties celfProp = new Properties();
celfProp.put("replicateAsynchronously", isAsync);
celfProp.put("asynchronousReplicationIntervalMillis", "1000");
CacheEventListener cel = celf.createCacheEventListener(celfProp);
cacheConvertUserId.getCacheEventNotificationService().registerListener(cel);
// add Custom EventListener
CacheEventListenerFactory ccelf = new CustomRMICacheReplicatorFactory();
Properties ccelfProp = new Properties();
ccelfProp.put("replicateAsynchronously", isAsync);
ccelfProp.put("asynchronousReplicationIntervalMillis", "1000");
CacheEventListener ccel = ccelf.createCacheEventListener(ccelfProp);
cacheConvertUserId.getCacheEventNotificationService().registerListener(ccel);
@SuppressWarnings("rawtypes")
BootstrapCacheLoaderFactory bclf = new RMIBootstrapCacheLoaderFactory();
Properties bclfProp = new Properties();
bclfProp.put("bootstrapAsynchronously", bootstrapAsynchronously);
bclfProp.put("maximumChunkSizeBytes", "5000000");
BootstrapCacheLoader bcl = bclf.createBootstrapCacheLoader(bclfProp);
cacheConvertUserId.setBootstrapCacheLoader(bcl);
manager.addCache(cacheConvertUserId);
if (logger.isWarn()) {
logger.warn(logPrefix + " cacheConvertUserId DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS = "
+ Cache.DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS);
}
}
private synchronized void initWebSocketTimeout(CacheManager manager, int sessionTimeout, int maxSize, String bootstrapAsynchronously) {
if (logger.isDebug()) {
logger.debug(logPrefix + " create webSocketTimeout cache sessionTimeout="+sessionTimeout +", maxSize=" + maxSize);
}
cacheWebSocketTimeout = new Cache(WEBSOCKER_CAHCE_NAME, maxSize, false, false, sessionTimeout, sessionTimeout);
String isAsync = PropManager.getInstance().getProperty("LOGIN", "IS_ASYNC", "false");
CacheEventListenerFactory celf = new RMICacheReplicatorFactory();
Properties celfProp = new Properties();
celfProp.put("replicateAsynchronously", isAsync);
celfProp.put("asynchronousReplicationIntervalMillis", "1000");// 비동기 방식을 사용할때 변경 내역을 다른 노드에 통지하는 주기 default 1000
CacheEventListener cel = celf.createCacheEventListener(celfProp);
cacheWebSocketTimeout.getCacheEventNotificationService().registerListener(cel);
// add Custom EventListener
CacheEventListenerFactory ccelf = new CustomRMICacheReplicatorFactory();
Properties ccelfProp = new Properties();
ccelfProp.put("replicateAsynchronously", isAsync);
ccelfProp.put("asynchronousReplicationIntervalMillis", "1000");
CacheEventListener ccel = ccelf.createCacheEventListener(ccelfProp);
cacheWebSocketTimeout.getCacheEventNotificationService().registerListener(ccel);
@SuppressWarnings("rawtypes")
BootstrapCacheLoaderFactory bclf = new RMIBootstrapCacheLoaderFactory();
Properties bclfProp = new Properties();
bclfProp.put("bootstrapAsynchronously", bootstrapAsynchronously);
bclfProp.put("maximumChunkSizeBytes", "5000000");
BootstrapCacheLoader bcl = bclf.createBootstrapCacheLoader(bclfProp);
cacheWebSocketTimeout.setBootstrapCacheLoader(bcl);
manager.addCache(cacheWebSocketTimeout);
if (logger.isWarn()) {
logger.warn(logPrefix + " cacheWebSocketTimeout DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS = "
+ Cache.DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS);
}
}
private synchronized void initTerminal(CacheManager manager, int sessionTimeout, int maxSize, String bootstrapAsynchronously) {
if (logger.isDebug()) {
logger.debug(logPrefix + " create TerminalSession cache sessionTimeout="+sessionTimeout +", maxSize=" + maxSize);
}
cacheTerminal = new Cache(TERMINAL_CAHCE_NAME, maxSize, false, false, sessionTimeout, sessionTimeout);
CacheEventListenerFactory celf = new RMICacheReplicatorFactory();
Properties celfProp = new Properties();
celfProp.put("replicateAsynchronously", "false");
celfProp.put("asynchronousReplicationIntervalMillis", "1000");
CacheEventListener cel = celf.createCacheEventListener(celfProp);
cacheTerminal.getCacheEventNotificationService().registerListener(cel);
// add Custom EventListener
CacheEventListenerFactory ccelf = new CustomRMICacheReplicatorFactory();
Properties ccelfProp = new Properties();
ccelfProp.put("replicateAsynchronously", "false");
ccelfProp.put("asynchronousReplicationIntervalMillis", "1000");
CacheEventListener ccel = ccelf.createCacheEventListener(ccelfProp);
cacheTerminal.getCacheEventNotificationService().registerListener(ccel);
@SuppressWarnings("rawtypes")
BootstrapCacheLoaderFactory bclf = new RMIBootstrapCacheLoaderFactory();
Properties bclfProp = new Properties();
bclfProp.put("bootstrapAsynchronously", bootstrapAsynchronously);
bclfProp.put("maximumChunkSizeBytes", "5000000");
BootstrapCacheLoader bcl = bclf.createBootstrapCacheLoader(bclfProp);
cacheTerminal.setBootstrapCacheLoader(bcl);
manager.addCache(cacheTerminal);
if (logger.isWarn()) {
logger.warn(logPrefix + " cacheTerminal DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS = "
+ Cache.DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS);
}
}
// WebSocket Login 관련
public SessionVO getLogin(String key) {
try {
Element element = cacheLogin.get(key);
if (element != null) {
return (SessionVO) element.getObjectValue();
}
return null;
} catch (CacheException e) {
logger.error(e.getMessage(), e);
return null;
} catch (Exception e) {
logger.error(e.getMessage(), e);
return null;
}
}
public void putLogin(String key, SessionVO value) {
putLogin(key, value, null);
}
public void putLogin(String key, SessionVO value, SessionInfoVO sessionInfoVO) {
if (logger.isWarn()) {
logger.warn("Put session key - " + key + ", Session - " + value.toString());
}
cacheLogin.put(new Element(key, value));
// terminal to userID 매핑 생성
if (value != null && value.getTerminalId() != null) {
cacheConvertUserId.put(new Element(value.getTerminalId(), key));
}
if (sessionInfoVO != null) {
SessionStatusManager.getInstance().manageStatus(sessionInfoVO);
} else {
SessionStatusManager.getInstance().manageLoginStatus(key);
}
}
public void removeLogin(String key) {
SessionVO vo = getLogin(key);
if (logger.isWarn()) {
logger.warn("Remove websocket login session key - " + key);
}
// terminal to userID 매핑 제거
if (vo != null && vo.getTerminalId() != null) {
cacheConvertUserId.remove(vo.getTerminalId());
}
cacheLogin.remove(key);
SessionStatusManager.getInstance().manageLoginStatus(key);
}
// terminalId 2 userId convert
public String getConvertUserId(String key) {
try {
Element element = cacheConvertUserId.get(key);
if (element != null) {
return (String) element.getObjectValue();
}
return null;
} catch (CacheException e) {
logger.error(e.getMessage(), e);
return null;
} catch (Exception e) {
logger.error(e.getMessage(), e);
return null;
}
}
public SessionVO getHttpLogin(String key) {
try {
Element element = httpLogin.get(key);
if (element != null) {
return (SessionVO) element.getObjectValue();
}
return null;
} catch (CacheException e) {
logger.error(e.getMessage(), e);
return null;
} catch (Exception e) {
logger.error(e.getMessage(), e);
return null;
}
}
public void putHttpLogin(String key, SessionVO value) {
logger.warn("Put session key - " + key + ", Session - " + value.toString());
httpLogin.put(new Element(key, value));
}
public void removeHTTPLogin(String key) {
logger.warn("Remove http login session key - " + key);
httpLogin.remove(key);
}
// Single Socket 관련
public SessionVO getConnectionInfo(String key) {
try {
Element element = cacheSocket.get(key);
if (element != null) {
SessionVO sessionVo = (SessionVO) element.getObjectValue();
return sessionVo;
}
return null;
} catch (Exception e) {
logger.error(e.getMessage(), e);
return null;
}
}
public SessionVO getConnectionStatus(String adapterGroupName) {
SessionVO sessionVo = null;
try {
sessionVo = getConnectionInfo(adapterGroupName);
if (sessionVo != null) {
String connectedInst = sessionVo.getLoginInstId();
// 싱글어댑터 Start --------------------------->
// EAIServerManager eaiServerManager = EAIServerManager.getInstance();
// String localServerName = eaiServerManager.getLocalServerName();
// 로컬서버가 연결시도 중인데 캐시에 자신의 인스턴스가 있을경우 삭제
if (localServerName.equals(connectedInst)) {
cacheSocket.remove(adapterGroupName);
return null;
}
// 싱글어댑터 End <---------------------------
// 케시에서 조회된 인스던스가 살았는지 확인 - 좀비캐시 삭제
if (logger.isWarn()) {
logger.warn("getConnectionInfo check primary server status - " + connectedInst);
}
boolean isAlive = HealthCheckManager.getInstance().getServerStatus(connectedInst);
if (!isAlive) {
if (logger.isWarn()) {
logger.warn("getConnectionInfo check primary server is Not Alive, clear cache.");
}
cacheSocket.remove(adapterGroupName);
return null;
}
}
return sessionVo;
} catch (Exception e) {
logger.error(e.getMessage(), e);
return null;
}
}
public void putConnectionInfo(String key, SessionVO value) {
if (logger.isWarn()) {
logger.warn("Put socket session key - " + key + ", Session - " + value.toString());
}
cacheSocket.put(new Element(key, value));
}
public void removeConnectionInfo(String key) {
if (logger.isWarn()) {
logger.warn("Remove socket session key - " + key);
}
cacheSocket.remove(key);
}
// Topic 관련
public EAIMessage getTopic(String key) {
try {
Element element = cacheTopic.get(key);
if (element != null) {
return (EAIMessage) element.getObjectValue();
}
return null;
} catch (Exception e) {
logger.error(e.getMessage(), e);
return null;
}
}
public void putTopic(String key, EAIMessage value) {
if (logger.isWarn()) {
logger.warn("Put Topic response - " + key + ", value - " + value.toString());
}
cacheTopic.put(new Element(key, value));
}
public void removeTopic(String key) {
if (logger.isWarn()) {
logger.warn("Remove Topic response key - " + key);
}
cacheTopic.remove(key);
}
@Override
public String getCacheStore(String key) {
try {
Element element = cacheStore.get(key);
if (element == null) {
return null;
} else {
// String message = (String)element.getObjectValue();
CacheStoreObject object = (CacheStoreObject) element.getObjectValue();
if (object.isExpired()) {
if (logger.isWarn())
logger.warn("getCacheStore expired key [" + key + "]");
cacheStore.remove(key);
return null;
} else {
return object.getMessage();
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
return null;
}
}
@Override
public void putCacheStore(String key, String value) {
putCacheStore(key, value, cacheStoreDurationSecs);
}
@Override
public void putCacheStore(String key, String value, int ttlSecs) {
if (logger.isWarn()) {
logger.warn("Put cacheStore key[" + key + "], value - " + value);
}
// cacheStore.put(new Element(key, value));
CacheStoreObject object = new CacheStoreObject(value, System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(ttlSecs));
cacheStore.put(new Element(key, object));
}
@Override
public void removeCacheStore(String key) {
if (logger.isWarn()) {
logger.warn("Remove cacheStore key - " + key);
}
cacheStore.remove(key);
}
public TerminalVO getTerminal(String key) {
try {
Element element = cacheTerminal.get(key);
if (element != null) {
return (TerminalVO) element.getObjectValue();
}
return null;
} catch (CacheException e) {
logger.error(e.getMessage(), e);
return null;
} catch (Exception e) {
logger.error(e.getMessage(), e);
return null;
}
}
public void putTerminal(String key, TerminalVO value, TerminalInfoVO terminalInfoVO) {
if (logger.isWarn()) {
logger.warn("Put terminal key - " + key + ", Terminal - " + value.toString());
}
cacheTerminal.put(new Element(key, value));
if (terminalInfoVO != null && EAIDBLogControl.isEnable()) {
try {
TerminalInfoDAO dao = ApplicationContextProvider.getContext().getBean(TerminalInfoDAO.class);
dao.upsertTerminalInfo(terminalInfoVO);
} catch (Exception e) {
logger.error(" insert Terminal DB ERROR. - " + e.getMessage(), e);
}
} else if (terminalInfoVO != null) {
logger.error("DB 장애로 업데이트 미수행 - " + value.toString());
}
}
public void removeTerminal(String key) {
if (logger.isWarn()) {
logger.warn("Remove socket teminal session key - " + key);
}
cacheTerminal.remove(key);
if (EAIDBLogControl.isEnable()) {
try {
TerminalInfoDAO dao = ApplicationContextProvider.getContext().getBean(TerminalInfoDAO.class);
TerminalInfoVO terminalInfoVO = new TerminalInfoVO(key);
terminalInfoVO.setSocSessionStatus(TerminalInfoVO.Status.inactive);
dao.upsertTerminalInfo(terminalInfoVO);
} catch (Exception e) {
logger.error(" insert Terminal DB ERROR. - " + key, e);
}
} else {
logger.error(" DB 장애로 인해 업데이트 미수행 - " + key);
}
}
private CacheInfoVO convert(Cache cache) {
CacheInfoVO v = new CacheInfoVO();
v.setName(cache.getName());
v.setSize(cache.getSize());
v.setTimeToLive(cache.getCacheConfiguration().getTimeToLiveSeconds() * 1000L);
v.setKeys(cache.getKeys());
return v;
}
public CacheInfoVO getLoginCache() {
return convert(cacheLogin);
}
public CacheInfoVO getHttpLoginCache() {
return convert(httpLogin);
}
public CacheInfoVO getEvictMasterCache() {
return convert(evictMasterCache);
}
public CacheInfoVO getTerminalCache() {
return convert(cacheTerminal);
}
public CacheInfoVO getConvertUserIdCache() {
return convert(cacheConvertUserId);
}
public CacheInfoVO getSocketCache() {
return convert(cacheSocket);
}
@Override
public void putWebSocketTimeout(String key, SessionVO value) {
cacheWebSocketTimeout.put(new Element(key, value));
}
@Override
public void removeWebSocketTimeout(String key) {
cacheWebSocketTimeout.remove(key);
}
public String getMasterInstId() {
Element element = evictMasterCache.get(MASTER_KEY);
if (element == null) {
return null;
} else {
return (String) element.getObjectValue();
}
}
public void closeManager() {
manager.shutdown();
}
@Override
public String getCacheStatus() {
StringBuilder sb = new StringBuilder();
String[] cacheNames = manager.getCacheNames();
sb.append("<Caches type=\"Ehcache\">").append("\n");
for(String cacheName : cacheNames) {
Cache cache = manager.getCache(cacheName);
// Get the cache size
long cacheSize = cache.getSize();
sb.append("<Cache name=\"" + cacheName + "\" Size=\"" + cacheSize).append("\"/>\n");
}
sb.append("</Caches>");
return sb.toString();
}
}
@@ -0,0 +1,813 @@
package com.eactive.eai.common.session;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import javax.cache.Cache;
import javax.cache.configuration.Factory;
import javax.cache.expiry.Duration;
import javax.cache.expiry.ModifiedExpiryPolicy;
import javax.cache.expiry.TouchedExpiryPolicy;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.IgniteEvents;
import org.apache.ignite.IgniteLogger;
import org.apache.ignite.Ignition;
import org.apache.ignite.cache.CacheAtomicityMode;
import org.apache.ignite.cache.CacheMetrics;
import org.apache.ignite.cache.CacheMode;
import org.apache.ignite.cache.CacheWriteSynchronizationMode;
import org.apache.ignite.cache.eviction.lru.LruEvictionPolicy;
import org.apache.ignite.cache.query.QueryCursor;
import org.apache.ignite.cache.query.ScanQuery;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.ClientConnectorConfiguration;
import org.apache.ignite.configuration.ConnectorConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.configuration.NearCacheConfiguration;
import org.apache.ignite.events.CacheEvent;
import org.apache.ignite.events.EventType;
import org.apache.ignite.kubernetes.configuration.KubernetesConnectionConfiguration;
import org.apache.ignite.lang.IgnitePredicate;
import org.apache.ignite.logger.slf4j.Slf4jLogger;
import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi;
import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
import org.apache.ignite.spi.discovery.tcp.ipfinder.kubernetes.TcpDiscoveryKubernetesIpFinder;
import org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder;
import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
import com.eactive.eai.adapter.socket2.common.Env;
import com.eactive.eai.common.logger.EAIDBLogControl;
import com.eactive.eai.common.message.EAIMessage;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.server.EAIServerVO;
import com.eactive.eai.common.sessioninfo.TerminalInfoDAO;
import com.eactive.eai.common.sessioninfo.TerminalInfoVO;
import com.eactive.eai.common.util.ApplicationContextProvider;
import com.eactive.eai.common.worker.Future;
import com.eactive.eai.common.worker.ResponseMap;
import com.eactive.eai.util.HealthCheckManager;
import ch.qos.logback.classic.Level;
// use Ignite
//------------------------------------------------------------------------------------
// Important :
// Persistence 를 사용할 경우, 일부서버 다운시 에러가 발생하므로 사용하지 않도록 한다.
// 에러내용 : Failed to execute the cache operation
// (all partition owners have left the grid, partition data has been lost)
//------------------------------------------------------------------------------------
public class SessionManagerForIgnite extends SessionManager {
// evictMaster Instance - single socket 관련
private static IgniteCache<String, String> evictMasterCache = null;
// Socket Session cache 정보
private static IgniteCache<String, SessionVO> cacheSocket = null;
// SyncAsync Type 거래 매핑을 위한 Topic 용 cache 정보
private static IgniteCache<String, EAIMessage> cacheTopic = null;
// 비동기 거래 복원용
private static IgniteCache<String, CacheStoreObject> cacheStore = null;
// webSocket Login cache 정보
private static IgniteCache<String, SessionVO> cacheLogin = null; // key = loginId
private static IgniteCache<String, String> cacheConvertUserId = null; // 단말ID 를 userID로 변경
// HTTP Polling 에 대한 timeout 관리용
private static IgniteCache<String, SessionVO> httpLogin = null; // key == uuid
// Terminal용 cache 정보 ATM, 무인공과금
private static IgniteCache<String, TerminalVO> cacheTerminal = null;
// HTTP Login 후 WebSocket Connection 일정 시간동안 없을시 Expired되며 자동 로그아웃 발생
private static IgniteCache<String, SessionVO> cacheWebSocketTimeout = null;
private static Ignite manager = null;
String localServerName = null;
private final String logPrefix = this.getClass().getName();
private boolean useMulticast = false;
private IgnitePredicate<CacheEvent> localListener = null;
private int cacheStoreDurationSecs = 60;
public void init(int communicationPort, int discoveryPort) {
int topicTimeout = 60;
int topicMaxSize = 10000;
int cacheStoreMaxSize = 10000;
PropManager pManager = PropManager.getInstance();
Properties prpty = pManager.getProperties(SessionManager.SESSION_MANAGER_GROUPNAME);
// 224.0.1.0 ~ 239.255.255.255
String mltIp = "230.0.0.1";
String workingDirectory = null;
int iPort = 4443;
int sessionTimeout = 60;
int webSocketTimeout = 60;
EAIServerManager eaiServerManager = EAIServerManager.getInstance();
localServerName = eaiServerManager.getLocalServerName();
EAIServerVO eaiServerVo = eaiServerManager.getEAIServer(localServerName);
if (prpty != null) {
workingDirectory = prpty.getProperty(SessionManager.CACHE_WORKING_DIR);
if (logger.isWarn()) {
logger.warn(">> CACHE_WORKING_DIR = " + workingDirectory);
}
mltIp = prpty.getProperty(SessionManager.SESSION_MANAGER_MULTI_GROUP_IP);
String sPort = prpty.getProperty(SessionManager.SESSION_MANAGER_MULTI_GROUP_PORT);
if (sPort != null) {
try {
iPort = Integer.parseInt(sPort);
} catch (NumberFormatException ex) {
iPort = 4443;
}
}
String sTimeout = prpty.getProperty(SessionManager.SESSION_MANAGER_SESSION_TIMEOUT);
if (sTimeout != null) {
try {
sessionTimeout = Integer.parseInt(sTimeout);
if (sessionTimeout < 30)
sessionTimeout = 30;
} catch (NumberFormatException ex) {
sessionTimeout = 60;
}
}
String wTimeout = prpty.getProperty(SessionManager.SESSION_MANAGER_WEBSOCKET_TIMEOUT);
if (wTimeout != null) {
try {
webSocketTimeout = Integer.parseInt(wTimeout);
} catch (NumberFormatException ex) {
webSocketTimeout = 60;
}
}
String topicTimeoutSec = prpty.getProperty(SessionManager.CACHE_TOPIC_DURATION);
if (topicTimeoutSec != null) {
try {
topicTimeout = Integer.parseInt(topicTimeoutSec);
if (topicTimeout < 0)
topicTimeout = 60;
} catch (NumberFormatException ex) {
topicTimeout = 60;
}
}
String topicMax = prpty.getProperty(SessionManager.TOPIC_MAXSZIE);
if (topicMax != null) {
try {
topicMaxSize = Integer.parseInt(topicMax);
if (topicMaxSize < 0)
topicMaxSize = 10000;
} catch (NumberFormatException ex) {
topicMaxSize = 10000;
}
}
String durationSecs = prpty.getProperty(SessionManager.CACHE_STORE_DURATION);
if (durationSecs != null) {
try {
cacheStoreDurationSecs = Integer.parseInt(durationSecs);
if (cacheStoreDurationSecs < 60)
cacheStoreDurationSecs = 60;
} catch (NumberFormatException ex) {
cacheStoreDurationSecs = 60;
}
}
}
String cacheStoreMax = prpty.getProperty(SessionManager.CAHCE_STORE_MAXSIZE);
if (cacheStoreMax != null) {
try {
cacheStoreMaxSize = Integer.parseInt(cacheStoreMax);
if (cacheStoreMaxSize < 0)
cacheStoreMaxSize = 10000;
} catch (NumberFormatException ex) {
cacheStoreMaxSize = 10000;
}
}
IgniteConfiguration config = new IgniteConfiguration();
if(StringUtils.isNotEmpty(workingDirectory)) {
config.setWorkDirectory(workingDirectory);
}
// System.setProperty("net.sf.ehcache.skipUpdateCheck", "true");
// CommunicationSpi
TcpCommunicationSpi communicationSpi = new TcpCommunicationSpi();
communicationSpi.setLocalPort(communicationPort);
communicationSpi.setIdleConnectionTimeout(15000);
communicationSpi.setConnectTimeout(1000);
communicationSpi.setReconnectCount(3);
communicationSpi.setMaxConnectTimeout(30000);
communicationSpi.setConnectionsPerNode(2);
communicationSpi.setSlowClientQueueLimit(1000);
String instanceLocalGroup = pManager.getProperty(SessionManager.SESSION_MANAGER_GROUPNAME, localServerName,
"DEFAULT");
// discoverySpi
TcpDiscoverySpi discoverySpi = new TcpDiscoverySpi();
discoverySpi.setLocalPort(discoveryPort);
discoverySpi.setClientReconnectDisabled(false);
discoverySpi.setSocketTimeout(5000);
discoverySpi.setNetworkTimeout(5000);
discoverySpi.setAckTimeout(5000);
discoverySpi.setMaxAckTimeout(15000);
discoverySpi.setReconnectCount(3);
if (!Env.isWindows() && BooleanUtils.toBoolean(System.getProperty("scalable", "false"))) {
// https://kubernetes.default.svc.cluster.local:443/api/v1/namespaces/card/endpoints/card-channel-runtime
String nameSpace = pManager.getProperty(SessionManager.SESSION_MANAGER_GROUPNAME, SESSION_MANAGER_KUBERNETES_NAMESPACE, "");
String serviceName = pManager.getProperty(SessionManager.SESSION_MANAGER_GROUPNAME, SESSION_MANAGER_KUBERNETES_SERVICENAME, "");
String masterUrl = pManager.getProperty(SessionManager.SESSION_MANAGER_GROUPNAME, SESSION_MANAGER_KUBERNETES_MASTERURL, "");
String accountToken = pManager.getProperty(SessionManager.SESSION_MANAGER_GROUPNAME, SESSION_MANAGER_KUBERNETES_ACCOUNTTOKEN, "");
if (logger.isDebug()) {
logger.debug(logPrefix + " >>>>Ignite INIT<<< Multicast nameSpace = " + nameSpace);
}
KubernetesConnectionConfiguration kubernetesCfg = new KubernetesConnectionConfiguration();
if (StringUtils.isNotBlank(nameSpace)) {
kubernetesCfg.setNamespace(nameSpace.trim());
}
if (StringUtils.isNotBlank(serviceName)) {
kubernetesCfg.setServiceName(serviceName.trim());
}
if (StringUtils.isNotBlank(masterUrl)) {
kubernetesCfg.setMasterUrl(masterUrl.trim());
}
if (StringUtils.isNotBlank(accountToken)) {
kubernetesCfg.setAccountToken(accountToken.trim());
}
TcpDiscoveryKubernetesIpFinder ipFinder = new TcpDiscoveryKubernetesIpFinder(kubernetesCfg);
if (logger.isWarn()) {
logger.warn(">> Use TcpDiscoveryKubernetesIpFinder setting nameSpace = " + nameSpace + ", serviceName = "
+ serviceName + ", masterUrl = " + masterUrl + ", accountToken = " + accountToken);
logger.warn(">> Use TcpDiscoveryKubernetesIpFinder config nameSpace = " + kubernetesCfg.getNamespace()
+ ", servcieName = " + kubernetesCfg.getServiceName() + ", masterUrl = "
+ kubernetesCfg.getMaster() + ", accountToken = " + kubernetesCfg.getAccountToken());
}
discoverySpi.setIpFinder(ipFinder);
}else {
// ipFinder
List<String> lists = new ArrayList<>();
for (String key : EAIServerManager.getInstance().getAllServer().keySet()) {
EAIServerVO vo = EAIServerManager.getInstance().getEAIServer(key);
if ("ALL".equals(key))
continue;
int discoverPort = vo.getCacheRemotePort();
String instanceGroup = pManager.getProperty(SessionManager.SESSION_MANAGER_GROUPNAME, key, "DEFAULT");
// 서버그룹별 Cluster 분리
if (instanceLocalGroup.equals(instanceGroup)) {
String server = null;
// 서버정보의 IP가 시스템과 다른 ip로 설정되면 기동이 안되는 문제
if (localServerName.equals(key) && !"GW".equals(System.getProperty("spring.profiles.active", ""))) {
server = "127.0.0.1:" + discoverPort;
} else {
server = vo.getAddress() + ":" + discoverPort;
}
lists.add(server);
if (logger.isWarn()) {
logger.warn("ipFind key= " + key + ", lists = " + server + ", instanceLocalGroup ="
+ instanceLocalGroup);
}
}
}
if (useMulticast) {
if (logger.isDebug()) {
logger.debug(logPrefix + " >>>>Ignite INIT<<< Multicast ip = " + mltIp);
}
TcpDiscoveryMulticastIpFinder ipFinder = new TcpDiscoveryMulticastIpFinder();
ipFinder.setMulticastGroup(mltIp);
ipFinder.setMulticastPort(iPort);
if (logger.isWarn()) {
logger.warn(">> Use TcpDiscoveryMulticastIpFinder mltIp = " + mltIp + ", port = " + iPort);
}
discoverySpi.setIpFinder(ipFinder);
} else {
if (lists.isEmpty()) {
if (logger.isWarn()) {
logger.warn(">> Single Server mode skip regist TcpDiscoveryVmIpFinder addresses");
}
} else {
TcpDiscoveryVmIpFinder ipFinder = new TcpDiscoveryVmIpFinder();
ipFinder.setAddresses(lists);
discoverySpi.setIpFinder(ipFinder);
if (logger.isWarn()) {
logger.warn(">> Use TcpDiscoveryVmIpFinder addresses = " + lists);
}
}
}
}
String bootstrapAsynchronously = "false";
ClientConnectorConfiguration cliConnCfg = new ClientConnectorConfiguration();
cliConnCfg.setPort(Integer.parseInt(eaiServerVo.getPort()) + 6);
config.setClientConnectorConfiguration(cliConnCfg);
ConnectorConfiguration connectorCfg = new ConnectorConfiguration();
connectorCfg.setPort(Integer.parseInt(eaiServerVo.getPort()) + 7);
config.setConnectorConfiguration(connectorCfg);
String serverGroupName = EAIServerManager.getInstance().getServerMappingType();
String instName = EAIServerManager.getInstance().getLocalServerName();
config.setGridName("elink_" + serverGroupName);// elink_mcc
config.setIgniteInstanceName(instName);// elink_mcc
config.setConsistentId(instName);
ch.qos.logback.classic.Logger blogger = (ch.qos.logback.classic.Logger) org.slf4j.LoggerFactory
.getLogger("org.apache.ignite");
blogger.setLevel(Level.INFO);
IgniteLogger log = new Slf4jLogger((org.slf4j.Logger) blogger);
config.setGridLogger(log);
config.setMetricsLogFrequency(10 * 60 * 1000); // 10분
config.setCommunicationSpi(communicationSpi);
config.setDiscoverySpi(discoverySpi);
config.setClientMode(false);
config.setIncludeEventTypes(EventType.EVT_CACHE_OBJECT_PUT, EventType.EVT_CACHE_OBJECT_REMOVED,
EventType.EVT_CACHE_OBJECT_EXPIRED
// , EventType.EVT_NODE_JOINED
// , EventType.EVT_NODE_LEFT
);
List<CacheConfiguration> caches = new ArrayList<>();
// Default
caches.add(initCache(config, 0, bootstrapAsynchronously, ADAPTER_MASTER_CAHCE_NAME, 10, false));
caches.add(initCache(config, 0, bootstrapAsynchronously, ADAPTER_CAHCE_NAME, 10000, false));
caches.add(initCache(config, topicTimeout, bootstrapAsynchronously, TOPIC_CAHCE_NAME, topicMaxSize, false));
if(logger.isWarn()) {
logger.warn(STORE_CAHCE_NAME +" - cacheStoreDurationSecs = " + cacheStoreDurationSecs);
}
caches.add(initCache(config, cacheStoreDurationSecs, bootstrapAsynchronously, STORE_CAHCE_NAME, cacheStoreMaxSize, false));
// for MCI
caches.add(initCache(config, sessionTimeout, bootstrapAsynchronously, LOGIN_CAHCE_NAME, 20000, false));
caches.add(initCache(config, sessionTimeout, bootstrapAsynchronously, HTTP_CAHCE_NAME, 20000, false));
caches.add(initCache(config, sessionTimeout, bootstrapAsynchronously, USERID_CAHCE_NAME, 20000, false));
caches.add(initCache(config, webSocketTimeout, bootstrapAsynchronously, WEBSOCKER_CAHCE_NAME, 20000, false));
caches.add(initCache(config, sessionTimeout, bootstrapAsynchronously, TERMINAL_CAHCE_NAME, 20000, false));
config.setCacheConfiguration(caches.stream().toArray(CacheConfiguration[]::new));
// Start a node.
if (logger.isWarn()) {
logger.warn(">> Ignition.starting...");
}
manager = Ignition.start(config);
manager.cluster().active(true);
if (logger.isWarn()) {
logger.warn(">> Ignition.started.");
}
IgniteEvents events = manager.events();
// Local listener that listens to local events.
localListener = new IgniteEvent();
// Subscribe to the cache events that are triggered on the local node.
events.localListen(localListener,
EventType.EVT_CACHE_OBJECT_PUT,
EventType.EVT_CACHE_OBJECT_REMOVED,
EventType.EVT_CACHE_OBJECT_EXPIRED);
evictMasterCache = manager.cache(ADAPTER_MASTER_CAHCE_NAME);
cacheSocket = manager.cache(ADAPTER_CAHCE_NAME);
cacheTopic = manager.cache(TOPIC_CAHCE_NAME);
cacheStore = manager.cache(STORE_CAHCE_NAME);
cacheLogin = manager.cache(LOGIN_CAHCE_NAME);
httpLogin = manager.cache(HTTP_CAHCE_NAME);
cacheConvertUserId = manager.cache(USERID_CAHCE_NAME);
cacheWebSocketTimeout = manager.cache(WEBSOCKER_CAHCE_NAME);
cacheTerminal = manager.cache(TERMINAL_CAHCE_NAME);
}
private CacheConfiguration initCache(IgniteConfiguration config, int expiryDurationSecs, String bootstrapAsynchronously,
String name, int maxsize, boolean useCacheWriteModeAsync) {
if (logger.isDebug()) {
logger.debug(logPrefix + " create " + name + " cache expiryDurationSecs=" + expiryDurationSecs);
}
// near-cache
NearCacheConfiguration nearConfiguration = new NearCacheConfiguration();
LruEvictionPolicy nearEvictionPolicy = new LruEvictionPolicy();
nearEvictionPolicy.setMaxSize(maxsize);
nearConfiguration.setNearEvictionPolicy(nearEvictionPolicy);
CacheConfiguration cacheConfig = new CacheConfiguration(name);
// REPLICATED,PARTITIONED(default)
// cacheConfig.setCacheMode(CacheMode.REPLICATED);
cacheConfig.setCacheMode(CacheMode.PARTITIONED);
// ATOMIC,TRANSACTIONAL
cacheConfig.setAtomicityMode(CacheAtomicityMode.ATOMIC);
// Set the number of backups (replicas) for each partition : default(0)
cacheConfig.setBackups(1);
// Enable reading from backups to improve read consistency : default(true)
cacheConfig.setReadFromBackup(true);
// FULL_SYNC/FULL_ASYNC/PRIMARY_SYNC(default)
if (useCacheWriteModeAsync) {
cacheConfig.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_ASYNC);
} else {
// cacheConfig.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC);
cacheConfig.setWriteSynchronizationMode(CacheWriteSynchronizationMode.PRIMARY_SYNC);
}
if(expiryDurationSecs > 0) {
cacheConfig
.setExpiryPolicyFactory(ModifiedExpiryPolicy.factoryOf(new Duration(TimeUnit.SECONDS, expiryDurationSecs)));
}
else {
cacheConfig
.setExpiryPolicyFactory( ModifiedExpiryPolicy.factoryOf(Duration.ETERNAL) );
}
cacheConfig.setNearConfiguration(nearConfiguration);
return cacheConfig;
}
// WebSocket Login 관련
public SessionVO getLogin(String key) {
try {
return cacheLogin.get(key);
} catch (Exception e) {
logger.error("getLogin null key=" + key, e);
return null;
}
}
public void putLogin(String key, SessionVO value) {
if (logger.isWarn()) {
logger.warn("Put session key - " + key + ", Session - " + value.toString());
}
cacheLogin.put(key, value);
// terminal to userID 매핑 생성
if (value != null && value.getTerminalId() != null) {
cacheConvertUserId.put(value.getTerminalId(), key);
}
}
public void removeLogin(String key) {
SessionVO vo = getLogin(key);
// terminal to userID 매핑 제거
if (vo != null && vo.getTerminalId() != null) {
cacheConvertUserId.remove(vo.getTerminalId());
}
cacheLogin.remove(key);
}
// terminalId 2 userId convert
public String getConvertUserId(String key) {
try {
return cacheConvertUserId.get(key);
} catch (Exception e) {
logger.error("getConvertUserId null key=" + key, e);
return null;
}
}
public SessionVO getHttpLogin(String key) {
try {
return httpLogin.get(key);
} catch (Exception e) {
logger.error("getHttpLogin null key=" + key, e);
return null;
}
}
public void putHttpLogin(String key, SessionVO value) {
if (logger.isWarn()) {
logger.warn("Put session key - " + key + ", Session - " + value.toString());
}
httpLogin.put(key, value);
}
public void removeHTTPLogin(String key) {
if (logger.isWarn()) {
logger.warn("Remove http login session key - " + key);
}
httpLogin.remove(key);
}
// Single Socket 관련
public SessionVO getConnectionInfo(String key) {
try {
return cacheSocket.get(key);
} catch (Exception e) {
logger.error("getConnectionInfo null key=" + key, e);
return null;
}
}
public SessionVO getConnectionStatus(String adapterGroupName) {
SessionVO sessionVo = null;
try {
sessionVo = getConnectionInfo(adapterGroupName);
if (sessionVo != null) {
String connectedInst = sessionVo.getLoginInstId();
// 싱글어댑터 Start --------------------------->
// EAIServerManager eaiServerManager = EAIServerManager.getInstance();
// String localServerName = eaiServerManager.getLocalServerName();
// 로컬서버가 연결시도 중인데 캐시에 자신의 인스던스가 있을경우 삭제
if (localServerName.equals(connectedInst)) {
cacheSocket.remove(adapterGroupName);
return null;
}
// 싱글어댑터 End <---------------------------
// 케시에서 조회된 인스던스가 살았는지 확인 - 좀비캐시 삭제
if (logger.isWarn()) {
logger.warn("getConnectionInfo check primary server status - " + connectedInst);
}
boolean isAlive = HealthCheckManager.getInstance().getServerStatus(connectedInst);
if (!isAlive) {
if (logger.isWarn()) {
logger.warn("getConnectionInfo check primary server is Not Alive, clear cache.");
}
cacheSocket.remove(adapterGroupName);
return null;
}
}
return sessionVo;
} catch (Exception e) {
logger.error(e.getMessage(), e);
return null;
}
}
public void putConnectionInfo(String key, SessionVO value) {
if (logger.isWarn()) {
logger.warn("Put socket session key - " + key + ", Session - " + value.toString());
}
try {
cacheSocket.put(key, value);
} catch (Exception e) {
logger.error("Put socket session error key=" + key + " Session - " + value.toString(), e);
}
}
public void removeConnectionInfo(String key) {
if (logger.isWarn()) {
logger.warn("Remove socket session key - " + key);
}
try {
cacheSocket.remove(key);
} catch (Exception e) {
logger.error("Remove socket session error key=" + key, e);
}
}
// Topic 관련
public EAIMessage getTopic(String key) {
try {
return cacheTopic.get(key);
} catch (Exception e) {
logger.error("getTopic null key=" + key, e);
return null;
}
}
public void putTopic(String key, EAIMessage value) {
if (logger.isWarn()) {
logger.warn("Put Topic response - " + key + ", value - " + value.toString());
}
// local event인 경우 ignite skip
Future future = ResponseMap.getInstance().get(key);
if(future != null) {
if (logger.isDebug()) {
logger.debug("PutTopic] local [" + key + "] put to Future");
}
future.getSlot().put(value);
return;
}
// remote Event
if (logger.isDebug()) {
logger.debug("PutTopic] remote [" + key + "] put to Future");
}
int retry = 3;
while(!cacheTopic.putIfAbsent(key, value) && retry > 0) {
retry--;
try {
Thread.sleep(300);
} catch (InterruptedException e) {
if(logger.isDebug()) {
logger.debug("PutTopic] sleep Fail");
}
}
if (logger.isDebug()) {
logger.debug("PutTopic] remote retry [" + key + "] put to Future");
}
};
removeTopic(key);
}
public void removeTopic(String key) {
if (logger.isWarn()) {
logger.warn("Remove Topic response key - " + key);
}
cacheTopic.remove(key);
}
// cacheStore 관련
public String getCacheStore(String key) {
try {
// Important : get 힌 후 바로 remove 하므로, 객체를 생성해서 return 해야 함.
// String message = cacheStore.get(key);
CacheStoreObject object = cacheStore.get(key);
if (object.isExpired()) {
if (logger.isWarn())
logger.warn("getCacheStore expired key [" + key + "]");
cacheStore.remove(key);
return null;
} else {
return object.getMessage();
}
} catch (Exception e) {
logger.error("getTopic null key [" + key + "]", e);
return null;
}
}
@Override
public void putCacheStore(String key, String value, int ttlSecs) {
if (logger.isWarn()) {
logger.warn("Put CacheStore key [" + key + "], value - " + value);
}
// cacheStore.put(key, value);
CacheStoreObject object = new CacheStoreObject(value, System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(ttlSecs));
cacheStore.put(key, object);
}
@Override
public void putCacheStore(String key, String value) {
putCacheStore(key, value, cacheStoreDurationSecs);
}
public void removeCacheStore(String key) {
if (logger.isWarn()) {
logger.warn("Remove CacheStore key [" + key + "]");
}
cacheStore.remove(key);
}
// Terminal
public TerminalVO getTerminal(String key) {
try {
return cacheTerminal.get(key);
} catch (Exception e) {
logger.error("getTerminal null key=" + key, e);
return null;
}
}
public void putTerminal(String key, TerminalVO value, TerminalInfoVO terminalInfoVO) {
if (logger.isWarn()) {
logger.warn("Put terminal key - " + key + ", Terminal - " + value.toString());
}
cacheTerminal.put(key, value);
if (terminalInfoVO != null && EAIDBLogControl.isEnable()) {
try {
TerminalInfoDAO dao = ApplicationContextProvider.getContext().getBean(TerminalInfoDAO.class);
dao.upsertTerminalInfo(terminalInfoVO);
} catch (Exception e) {
logger.error(" insert Terminal DB ERROR. - " + e.getMessage(), e);
}
} else if (terminalInfoVO != null) {
logger.error("DB 장애로 업데이트 미수행 - " + value.toString());
}
}
public void removeTerminal(String key) {
if (logger.isWarn()) {
logger.warn("Remove socket teminal session key - " + key);
}
try {
// 서버다운시 org.apache.ignite.internal.processors.cache.CacheStoppedException 때문에
// try catch 추가 : jun's 20220826
cacheTerminal.remove(key);
} catch (Exception e) {
logger.error(" cacheTerminal remove error. - " + key, e);
}
if (EAIDBLogControl.isEnable()) {
try {
TerminalInfoDAO dao = ApplicationContextProvider.getContext().getBean(TerminalInfoDAO.class);
TerminalInfoVO terminalInfoVO = new TerminalInfoVO(key);
terminalInfoVO.setSocSessionStatus(TerminalInfoVO.Status.inactive);
dao.upsertTerminalInfo(terminalInfoVO);
} catch (Exception e) {
logger.error(" insert Terminal DB ERROR. - " + key, e);
}
} else {
logger.error(" DB 장애로 인해 업데이트 미수행 - " + key);
}
}
@SuppressWarnings("rawtypes")
private CacheInfoVO convert(IgniteCache cache) {
CacheInfoVO v = new CacheInfoVO();
long timeToLive = 0;
CacheConfiguration cf = (CacheConfiguration) cache.getConfiguration(CacheConfiguration.class);
Factory factory = cf.getExpiryPolicyFactory();
Object obj = factory.create();
if (obj instanceof TouchedExpiryPolicy) {
TouchedExpiryPolicy cep = (TouchedExpiryPolicy) obj;
Duration dur = cep.getExpiryForCreation();
timeToLive = dur.getTimeUnit().toMillis(dur.getDurationAmount());
}
v.setTimeToLive(timeToLive);
v.setName(cache.getName());
List<String> keys = new ArrayList<>();
QueryCursor<Cache.Entry<String, SessionVO>> cursor = cache.query(new ScanQuery<>());
cursor.forEach(entry -> keys.add(entry.getKey()));
v.setKeys(keys);
v.setSize(keys.size());
return v;
}
public CacheInfoVO getLoginCache() {
return convert(cacheLogin);
}
public CacheInfoVO getHttpLoginCache() {
return convert(httpLogin);
}
public CacheInfoVO getEvictMasterCache() {
return convert(evictMasterCache);
}
public CacheInfoVO getTerminalCache() {
return convert(cacheTerminal);
}
public CacheInfoVO getConvertUserIdCache() {
return convert(cacheConvertUserId);
}
public CacheInfoVO getSocketCache() {
return convert(cacheSocket);
}
@Override
public void putWebSocketTimeout(String key, SessionVO value) {
cacheWebSocketTimeout.put(key, value);
}
@Override
public void removeWebSocketTimeout(String key) {
cacheWebSocketTimeout.remove(key);
}
public String getMasterInstId() {
try {
return evictMasterCache.get(MASTER_KEY);
} catch (Exception e) {
logger.error("getMasterInstId null key=" + MASTER_KEY, e);
return null;
}
}
public void closeManager() {
if(localListener != null) {
((IgniteEvent) localListener).shutdown();
}
manager.close();
}
@Override
public String getCacheStatus() {
StringBuilder sb = new StringBuilder();
Iterable<String> cacheNames = manager.cacheNames();
sb.append("<Caches type=\"Ignite\">").append("\n");
for (String cacheName : cacheNames) {
IgniteCache<Object, Object> cache = manager.cache(cacheName);
CacheMetrics metrics = cache.metrics();
long cacheSize = metrics.getSize();
sb.append("<Cache name=\"" + cacheName + "\" Size=\"" + cacheSize).append("\"/>\n");
}
sb.append("</Caches>");
return sb.toString();
}
}
@@ -0,0 +1,79 @@
package com.eactive.eai.common.session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.eactive.eai.common.logger.EAIDBLogControl;
import com.eactive.eai.common.sessioninfo.SessionInfoDAO;
import com.eactive.eai.common.sessioninfo.SessionInfoVO;
import com.eactive.eai.common.sessioninfo.SessionInfoVO.Status;
import com.eactive.eai.common.util.ApplicationContextProvider;
import com.eactive.eai.common.util.Logger;
@Component
public class SessionStatusManager {
private static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);
// private static SessionStatusManager instance;
@Autowired
SessionInfoDAO sessionInfoDAO;
private SessionStatusManager() {
}
public static SessionStatusManager getInstance() {
return ApplicationContextProvider.getContext().getBean(SessionStatusManager.class);
}
public void manageStatus(SessionInfoVO sessionInfoVO) {
if (EAIDBLogControl.isEnable()) {
try {
sessionInfoDAO.upsertSessionInfo(sessionInfoVO);
} catch (Exception e) {
if (logger.isError()) {
logger.error("Insert Session DB ERROR. - " + sessionInfoVO.getUserId(), e);
}
}
} else {
if (logger.isError()) {
logger.error("EAIDBLogControl is not enable - " + sessionInfoVO.getUserId());
}
}
}
public void manageLoginStatus(String userId) {
SessionVO login = SessionManager.getInstance().getLogin(userId);
Status status = login == null ? SessionInfoVO.Status.inactive : SessionInfoVO.Status.active;
SessionInfoVO sessionInfoVO = new SessionInfoVO(userId);
sessionInfoVO.setSessionStatus(status);
/** upsert **/
manageStatus(sessionInfoVO);
}
public void manageLoginStatusWithUUID(SessionVO session) {
SessionVO login = SessionManager.getInstance().getHttpLogin(session.getUuid());
Status status = login == null ? SessionInfoVO.Status.inactive : SessionInfoVO.Status.active;
String userId = login == null ? session.getLoginUserId() : login.getLoginUserId();
SessionInfoVO sessionInfoVO = new SessionInfoVO(session.getLoginUserId());
sessionInfoVO.setSessionId(session.getUuid());
sessionInfoVO.setUserId(userId);
sessionInfoVO.setSessionStatus(status);
/** upsert **/
manageStatus(sessionInfoVO);
}
public void manageWebSocketStatus(String userId, Status status) {
SessionInfoVO sessionInfoVO = new SessionInfoVO(userId);
sessionInfoVO.setWsocSessionStatus(status);
/** upsert **/
manageStatus(sessionInfoVO);
}
}
@@ -0,0 +1,133 @@
package com.eactive.eai.common.session;
import java.io.Serializable;
/**
* 1. 기능 : SessionVO 객체
* 2. 처리 개요 :
* 3. 주의사항
*
* @author :
* @version : v 1.0.0
* @see : 관련 기능을 참조
* @since :
* :
*/
public class SessionVO implements Serializable
{
/**
*
*/
private static final long serialVersionUID = 8397247737238565420L;
private String loginUserId;
private String loginInstId;
private String wsInstId;
private String wsAdapterGroupName;
private String uuid;
private String primaryInst; // 싱글어댑터
//국코드 추가
private String brncd;
// private String sessionAES;
// private String httpSessionId;
private String terminalId;
public SessionVO() {
super();
}
public SessionVO(String loginUserId, String loginInstId, String uuid) {
super();
this.loginUserId = loginUserId;
this.loginInstId = loginInstId;
this.uuid = uuid;
}
public String getLoginUserId() {
return loginUserId;
}
public void setLoginUserId(String loginUserId) {
this.loginUserId = loginUserId;
}
public String getLoginInstId() {
return loginInstId;
}
public void setLoginInstId(String loginInstId) {
this.loginInstId = loginInstId;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
// public String getSessionAES() {
// return sessionAES;
// }
//
// public void setSessionAES(String sessionAES) {
// this.sessionAES = sessionAES;
// }
//
//
// public String getHttpSessionId() {
// return httpSessionId;
// }
//
// public void setHttpSessionId(String httpSessionId) {
// this.httpSessionId = httpSessionId;
// }
public String getWsInstId() {
return wsInstId;
}
public void setWsInstId(String wsInstId) {
this.wsInstId = wsInstId;
}
public String getWsAdapterGroupName() {
return wsAdapterGroupName;
}
public void setWsAdapterGroupName(String wsAdapterGroupName) {
this.wsAdapterGroupName = wsAdapterGroupName;
}
public String getBrncd() {
return brncd;
}
public void setBrncd(String brncd) {
this.brncd = brncd;
}
public String getTerminalId() {
return terminalId;
}
public void setTerminalId(String terminalId) {
this.terminalId = terminalId;
}
public String getPrimaryInst() {
return primaryInst;
}
public void setPrimaryInst(String primaryInst) {
this.primaryInst = primaryInst;
}
@Override
public String toString() {
return "SessionVO [loginUserId=" + loginUserId + ", loginInstId=" + loginInstId + ", wsInstId=" + wsInstId
+ ", wsAdapterGroupName=" + wsAdapterGroupName + ", uuid=" + uuid + ", brncd=" + brncd + ", terminalId="
+ terminalId + ", primaryInst="+ primaryInst +"]";
}
}
@@ -0,0 +1,250 @@
package com.eactive.eai.common.session;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.mina.common.IoSession;
import com.eactive.eai.adapter.socket2.common.ExpiringMap;
import com.eactive.eai.common.lifecycle.Lifecycle;
import com.eactive.eai.common.lifecycle.LifecycleException;
import com.eactive.eai.common.lifecycle.LifecycleListener;
import com.eactive.eai.common.lifecycle.LifecycleSupport;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.sessioninfo.SessionInfoVO;
import com.eactive.eai.common.util.DatetimeUtil;
import com.eactive.eai.common.util.Logger;
/**
* 1. 기능 : websocket session 정보를 관리하는 Manager 클래스
* 2. 처리 개요 : ehcache 로 session 을 공유함.
* 3. 주의사항
*
* @author :
* @version : v 1.0.0
* @see : 관련 기능을 참조
* @since :
* :
*/
public class TcpSessionManager implements Lifecycle
{
/**
* Default Logger
*/
static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
/**
* SessionManager Single Instance
*/
private static TcpSessionManager instance;
/**
* cache 정보
*/
private static ExpiringMap<String,String> uidCache ; //<sessionString, uid>
private static ExpiringMap<String, IoSession> chnCache ; //<uid, session>
/**
* 기동 여부
*/
private boolean started;
/**
* LifeccyleSupport object
*/
private LifecycleSupport lifecycle = new LifecycleSupport(this);
/**
* 1. 기능 : Default Constructor
* 2. 처리 개요 : 라우팅 Rule 정보를 저장하기 위한 HashMap을 초기화한다.
* 3. 주의사항
*
**/
private TcpSessionManager() {
//init();
}
/**
* 1. 기능 : SessionManager Singleton Object를 반환하는 getter method
* 2. 처리 개요 : SessionManager Singleton Object를 반환한다.
* 3. 주의사항
*
* @return SessionManager Singleton object
**/
public static TcpSessionManager getInstance() {
if(instance == null) {
synchronized(TcpSessionManager.class) {
if(instance==null) {
instance = new TcpSessionManager();
}
}
}
return instance;
}
/**
* 1. 기능 : Lifecycle의 start 메서드로 RoutingMangaer를 초기화하는 메서드
* 2. 처리 개요 : RoutingDAO를 이용해 추출 Rule 정보 모두를 가져와 초기화한다.
* 3. 주의사항
*
* @exception LifecycleException 이미 시작되었거나(RECEAICBM201), RoutingDAO를 통해 Rule 정보를 가져오다 DAOExcepiton이 발생될 경우(RECEAICRT201)
*
**/
public void start() throws LifecycleException {
if (started)
throw new LifecycleException("RECEAICRT201");
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(STARTING_EVENT, this);
this.uidCache = new ExpiringMap<String,String>(86400,600);
this.chnCache = new ExpiringMap<String,IoSession>(86400,600);
// this.uuidCache = new ExpiringMap<String,IoSession>(60,1);
// this.chnCache = new ExpiringMap<String,IoSession>(60,1);
started = true;
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(STARTED_EVENT, this);
}
/**
* 1. 기능 : Lifecycle의 stop 메서드로 SessionManager를 종료하는 메서드
* 2. 처리 개요 : 멤버에 캐싱한 라우팅 Rule 정보를 clear한다.
* 3. 주의사항
*
* @exception LifecycleException 이미 종료된 경우 발생(RECEAICRT203)
**/
public void stop() throws LifecycleException {
// Validate and update our current component state
if (!started)
throw new LifecycleException("RECEAICRT203");
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(STOPING_EVENT, this);
started = false;
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(STOPPED_EVENT, this);
}
/**
* 1. 기능 : LifecycleListener를 등록하는 메서드
* 2. 처리 개요 : LifecycleListener를 등록한다.
* 3. 주의사항
*
* @param listener LifecycleEvent를 수신한 LifecycleListener
**/
public void addLifecycleListener(LifecycleListener listener)
{
lifecycle.addLifecycleListener(listener);
}
/**
* 1. 기능 : 등록된 LifecycleListener 리스트를 반환하는 메서드
* 2. 처리 개요 : 등록된 LifecycleListener 리스트를 반환하다.
* 3. 주의사항
*
* @return 등록된 LifecycleListener 리스트
**/
public LifecycleListener[] findLifecycleListeners()
{
return lifecycle.findLifecycleListeners();
}
/**
* 1. 기능 : 등록된 LifecycleListener를 삭제하는 메서드
* 2. 처리 개요 : 파라미터의 LifecycleListener를 삭제한다.
* 3. 주의사항
*
* @param listener 삭제할 LifecycleListener
**/
public void removeLifecycleListener(LifecycleListener listener)
{
lifecycle.removeLifecycleListener(listener);
}
/**
* 1. 기능 : SessionManager의 초기화 여부를 반환하는 getter 메서드
* 2. 처리 개요 : SessionManager의 초기화 여부를 반환한다.
* 3. 주의사항
*
* @return 초기화 여부
**/
public boolean isStarted() {
return this.started;
}
public ExpiringMap getSessionList(){
return chnCache;
}
public synchronized void sessionOpen(IoSession session){
logger.warn("TcpSessionManager ] session Opened - [ " + session + "]");
}
// public synchronized void sessionLogin(String uuid, String usrid, IoSession session){
// if(usrid == null && session == null){
// return;
// }
// this.uidCache.put(session.toString(), usrid);
// this.chnCache.put(usrid, session);
//
// logger.warn("TcpSessionManager ] session saved " + uuid + "["+usrid+"] : " + session);
//
//
// EAIServerManager eaiServerManager = EAIServerManager.getInstance();
// String serverName = eaiServerManager.getLocalServerName();
//
// SessionVO sessionVo = new SessionVO();
// sessionVo.setUuid(uuid);
// sessionVo.setLoginUserId(usrid);
// sessionVo.setLoginInstId(serverName);
//
// SessionInfoVO sessionInfoVO = new SessionInfoVO(usrid);
// sessionInfoVO.setSessionId(uuid);
// sessionInfoVO.setCreateTime(DatetimeUtil.getCurrentDateTime());
//
// SessionManager.getInstance().putLogin(session.toString(), sessionVo, sessionInfoVO);
//
// }
public synchronized void sessionClose(IoSession session){
try{
String sessionId = session.toString();
String userId = null;
try{
userId = this.uidCache.get(sessionId);
this.uidCache.remove(sessionId);
}catch(NullPointerException e){
logger.error("TcpSessionManager ] tried to remove Cache , but UIDCache value of ["+sessionId+"] is null ");
}
try{
if(userId != null) this.chnCache.remove(userId);
}catch(NullPointerException e){
logger.error("TcpSessionManager ] tried to remove Cache , but ChnCache value of ["+sessionId+"] is null ");
}
try{
if(userId != null) {
ChannelSessionFacade.getInstance().removeFromLoginCache(userId);
}
}catch(NullPointerException e){
logger.error("TcpSessionManager ] tried to remove Cache , but ehCache value of ["+sessionId+"] is null ");
}
}catch(Exception e){
logger.error("TcpSessionManager ] Error occured in removing Session Info - " + session);
}
}
public synchronized String getUid(String sessionId){
String uid = uidCache.get(sessionId);
return uid;
}
public synchronized IoSession getSession(String sessionId){
IoSession session = chnCache.get(sessionId);
return session;
}
}
@@ -0,0 +1,87 @@
package com.eactive.eai.common.session;
import java.io.Serializable;
/**
* 1. 기능 : SessionVO 객체 2. 처리 개요 : 3. 주의사항
*
* @author :
* @version : v 1.0.0
* @see : 관련 기능을 참조
* @since : :
*/
public class TerminalVO implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1;
private String terminalNo;
private String rofcCd;// 청코드
private String brncd;// 국코드
private String brnName;// 국명
private boolean isOpenTran;// 개국거래여부
private boolean isOpen; //개국여부
public TerminalVO() {
super();
}
public String getTerminalNo() {
return terminalNo;
}
public void setTerminalNo(String terminalNo) {
this.terminalNo = terminalNo;
}
public String getRofcCd() {
return rofcCd;
}
public void setRofcCd(String rofcCd) {
this.rofcCd = rofcCd;
}
public String getBrncd() {
return brncd;
}
public void setBrncd(String brncd) {
this.brncd = brncd;
}
public String getBrnName() {
return brnName;
}
public void setBrnName(String brnName) {
this.brnName = brnName;
}
public boolean isOpenTran() {
return isOpenTran;
}
public void setOpenTran(boolean isOpenTran) {
this.isOpenTran = isOpenTran;
}
public boolean isOpen() {
return isOpen;
}
public void setOpen(boolean isOpen) {
this.isOpen = isOpen;
}
@Override
public String toString() {
return "TerminalVO [terminalNo=" + terminalNo + ", rofcCd=" + rofcCd + ", brncd=" + brncd + ", brnName="
+ brnName + ", isOpenTran=" + isOpenTran + ", isOpen=" + isOpen + "]";
}
}
@@ -0,0 +1,144 @@
/**
* Copyright Terracotta, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.eactive.eai.common.session;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.distribution.CachePeer;
import net.sf.ehcache.distribution.RMICacheManagerPeerProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.MalformedURLException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
/**
* A provider of Peer RMI addresses based off manual configuration.
* <p/>
* Because there is no monitoring of whether a peer is actually there, the list of peers is dynamically
* looked up and verified each time a lookup request is made.
* <p/>
*
* @author Greg Luck
* @version $Id: ManualRMICacheManagerPeerProvider.java 5594 2012-05-07 16:04:31Z cdennis $
*/
public final class TimeoutManualRMICacheManagerPeerProvider extends RMICacheManagerPeerProvider {
private static final Logger LOG = LoggerFactory.getLogger(TimeoutManualRMICacheManagerPeerProvider.class.getName());
/**
* Empty constructor.
*/
public TimeoutManualRMICacheManagerPeerProvider() {
super();
}
/**
* {@inheritDoc}
*/
public final void init() {
//nothing to do here
}
/**
* Time for a cluster to form. This varies considerably, depending on the implementation.
*
* @return the time in ms, for a cluster to form
*/
public long getTimeForClusterToForm() {
return 0;
}
/**
* Register a new peer.
*
* @param rmiUrl
*/
public final synchronized void registerPeer(String rmiUrl) {
peerUrls.put(rmiUrl, new Date());
}
/**
* @return a list of {@link CachePeer} peers, excluding the local peer.
*/
public final synchronized List listRemoteCachePeers(Ehcache cache) throws CacheException {
List remoteCachePeers = new ArrayList();
List staleList = new ArrayList();
for (Iterator iterator = peerUrls.keySet().iterator(); iterator.hasNext();) {
String rmiUrl = (String) iterator.next();
String rmiUrlCacheName = extractCacheName(rmiUrl);
if (!rmiUrlCacheName.equals(cache.getName())) {
continue;
}
Date date = (Date) peerUrls.get(rmiUrl);
if (!stale(date)) {
CachePeer cachePeer = null;
try {
cachePeer = lookupRemoteCachePeer(rmiUrl);
remoteCachePeers.add(cachePeer);
} catch (Exception e) {
if (LOG.isDebugEnabled()) {
LOG.debug("Looking up rmiUrl " + rmiUrl + " through exception " + e.getMessage()
+ ". This may be normal if a node has gone offline. Or it may indicate network connectivity"
+ " difficulties", e);
}
}
} else {
LOG.debug("rmiUrl {} should never be stale for a manually configured cluster.", rmiUrl);
staleList.add(rmiUrl);
}
}
//Remove any stale remote peers. Must be done here to avoid concurrent modification exception.
for (int i = 0; i < staleList.size(); i++) {
String rmiUrl = (String) staleList.get(i);
peerUrls.remove(rmiUrl);
}
return remoteCachePeers;
}
/**
* Whether the entry should be considered stale.
* <p/>
* Manual RMICacheManagerProviders use a static list of urls and are therefore never stale.
*
* @param date the date the entry was created
* @return true if stale
*/
protected final boolean stale(Date date) {
return false;
}
static String extractCacheName(String rmiUrl) {
return rmiUrl.substring(rmiUrl.lastIndexOf('/') + 1);
}
public CachePeer lookupRemoteCachePeer(String url) throws MalformedURLException, NotBoundException, RemoteException {
LOG.debug("Lookup URL {}", url);
CachePeer cachePeer = (CachePeer) TimeoutNaming.lookup(url);
return cachePeer;
}
}
@@ -0,0 +1,366 @@
/*
* Copyright 1996-2005 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.eactive.eai.common.session;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.rmi.AccessException;
import java.rmi.AlreadyBoundException;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
/**
* The <code>Naming</code> class provides methods for storing and obtaining
* references to remote objects in a remote object registry. Each method of
* the <code>Naming</code> class takes as one of its arguments a name that
* is a <code>java.lang.String</code> in URL format (without the
* scheme component) of the form:
*
* <PRE>
* //host:port/name
* </PRE>
*
* <P>where <code>host</code> is the host (remote or local) where the registry
* is located, <code>port</code> is the port number on which the registry
* accepts calls, and where <code>name</code> is a simple string uninterpreted
* by the registry. Both <code>host</code> and <code>port</code> are optional.
* If <code>host</code> is omitted, the host defaults to the local host. If
* <code>port</code> is omitted, then the port defaults to 1099, the
* "well-known" port that RMI's registry, <code>rmiregistry</code>, uses.
*
* <P><em>Binding</em> a name for a remote object is associating or
* registering a name for a remote object that can be used at a later time to
* look up that remote object. A remote object can be associated with a name
* using the <code>Naming</code> class's <code>bind</code> or
* <code>rebind</code> methods.
*
* <P>Once a remote object is registered (bound) with the RMI registry on the
* local host, callers on a remote (or local) host can lookup the remote
* object by name, obtain its reference, and then invoke remote methods on the
* object. A registry may be shared by all servers running on a host or an
* individual server process may create and use its own registry if desired
* (see <code>java.rmi.registry.LocateRegistry.createRegistry</code> method
* for details).
*
* @author Ann Wollrath
* @author Roger Riggs
* @since JDK1.1
* @see java.rmi.registry.Registry
* @see java.rmi.registry.LocateRegistry
* @see java.rmi.registry.LocateRegistry#createRegistry(int)
*/
public final class TimeoutNaming {
/**
* Disallow anyone from creating one of these
*/
private TimeoutNaming() {}
/**
* Returns a reference, a stub, for the remote object associated
* with the specified <code>name</code>.
*
* @param name a name in URL format (without the scheme component)
* @return a reference for a remote object
* @exception NotBoundException if name is not currently bound
* @exception RemoteException if registry could not be contacted
* @exception AccessException if this operation is not permitted
* @exception MalformedURLException if the name is not an appropriately
* formatted URL
* @since JDK1.1
*/
public static Remote lookup(String name)
throws NotBoundException,
java.net.MalformedURLException,
RemoteException
{
ParsedNamingURL parsed = parseURL(name);
Registry registry = getRegistry(parsed);
if (parsed.name == null)
return registry;
return registry.lookup(parsed.name);
}
/**
* Binds the specified <code>name</code> to a remote object.
*
* @param name a name in URL format (without the scheme component)
* @param obj a reference for the remote object (usually a stub)
* @exception AlreadyBoundException if name is already bound
* @exception MalformedURLException if the name is not an appropriately
* formatted URL
* @exception RemoteException if registry could not be contacted
* @exception AccessException if this operation is not permitted (if
* originating from a non-local host, for example)
* @since JDK1.1
*/
public static void bind(String name, Remote obj)
throws AlreadyBoundException,
java.net.MalformedURLException,
RemoteException
{
ParsedNamingURL parsed = parseURL(name);
Registry registry = getRegistry(parsed);
if (obj == null)
throw new NullPointerException("cannot bind to null");
registry.bind(parsed.name, obj);
}
/**
* Destroys the binding for the specified name that is associated
* with a remote object.
*
* @param name a name in URL format (without the scheme component)
* @exception NotBoundException if name is not currently bound
* @exception MalformedURLException if the name is not an appropriately
* formatted URL
* @exception RemoteException if registry could not be contacted
* @exception AccessException if this operation is not permitted (if
* originating from a non-local host, for example)
* @since JDK1.1
*/
public static void unbind(String name)
throws RemoteException,
NotBoundException,
java.net.MalformedURLException
{
ParsedNamingURL parsed = parseURL(name);
Registry registry = getRegistry(parsed);
registry.unbind(parsed.name);
}
/**
* Rebinds the specified name to a new remote object. Any existing
* binding for the name is replaced.
*
* @param name a name in URL format (without the scheme component)
* @param obj new remote object to associate with the name
* @exception MalformedURLException if the name is not an appropriately
* formatted URL
* @exception RemoteException if registry could not be contacted
* @exception AccessException if this operation is not permitted (if
* originating from a non-local host, for example)
* @since JDK1.1
*/
public static void rebind(String name, Remote obj)
throws RemoteException, java.net.MalformedURLException
{
ParsedNamingURL parsed = parseURL(name);
Registry registry = getRegistry(parsed);
if (obj == null)
throw new NullPointerException("cannot bind to null");
registry.rebind(parsed.name, obj);
}
/**
* Returns an array of the names bound in the registry. The names are
* URL-formatted (without the scheme component) strings. The array contains
* a snapshot of the names present in the registry at the time of the
* call.
*
* @param name a registry name in URL format (without the scheme
* component)
* @return an array of names (in the appropriate format) bound
* in the registry
* @exception MalformedURLException if the name is not an appropriately
* formatted URL
* @exception RemoteException if registry could not be contacted.
* @since JDK1.1
*/
public static String[] list(String name)
throws RemoteException, java.net.MalformedURLException
{
ParsedNamingURL parsed = parseURL(name);
Registry registry = getRegistry(parsed);
String prefix = "";
if (parsed.port > 0 || !parsed.host.equals(""))
prefix += "//" + parsed.host;
if (parsed.port > 0)
prefix += ":" + parsed.port;
prefix += "/";
String[] names = registry.list();
for (int i = 0; i < names.length; i++) {
names[i] = prefix + names[i];
}
return names;
}
/**
* Returns a registry reference obtained from information in the URL.
*
* jun's
* Timeout RMI Socket Factory 를 추가함
*/
private static Registry getRegistry(ParsedNamingURL parsed)
throws RemoteException
{
return LocateRegistry.getRegistry(parsed.host, parsed.port, new TimeoutRMISocketFactory(3*1000,10*1000));
}
/**
* Dissect Naming URL strings to obtain referenced host, port and
* object name.
*
* @return an object which contains each of the above
* components.
*
* @exception MalformedURLException if given url string is malformed
*/
private static ParsedNamingURL parseURL(String str)
throws MalformedURLException
{
try {
return intParseURL(str);
} catch (URISyntaxException ex) {
/* With RFC 3986 URI handling, 'rmi://:<port>' and
* '//:<port>' forms will result in a URI syntax exception
* Convert the authority to a localhost:<port> form
*/
MalformedURLException mue = new MalformedURLException(
"invalid URL String: " + str);
mue.initCause(ex);
int indexSchemeEnd = str.indexOf(':');
int indexAuthorityBegin = str.indexOf("//:");
if (indexAuthorityBegin < 0) {
throw mue;
}
if ((indexAuthorityBegin == 0) ||
((indexSchemeEnd > 0) &&
(indexAuthorityBegin == indexSchemeEnd + 1))) {
int indexHostBegin = indexAuthorityBegin + 2;
String newStr = str.substring(0, indexHostBegin) +
"localhost" +
str.substring(indexHostBegin);
try {
return intParseURL(newStr);
} catch (URISyntaxException inte) {
throw mue;
} catch (MalformedURLException inte) {
throw inte;
}
}
throw mue;
}
}
private static ParsedNamingURL intParseURL(String str)
throws MalformedURLException, URISyntaxException
{
URI uri = new URI(str);
if (uri.isOpaque()) {
throw new MalformedURLException(
"not a hierarchical URL: " + str);
}
if (uri.getFragment() != null) {
throw new MalformedURLException(
"invalid character, '#', in URL name: " + str);
} else if (uri.getQuery() != null) {
throw new MalformedURLException(
"invalid character, '?', in URL name: " + str);
} else if (uri.getUserInfo() != null) {
throw new MalformedURLException(
"invalid character, '@', in URL host: " + str);
}
String scheme = uri.getScheme();
if (scheme != null && !scheme.equals("rmi")) {
throw new MalformedURLException("invalid URL scheme: " + str);
}
String name = uri.getPath();
if (name != null) {
if (name.startsWith("/")) {
name = name.substring(1);
}
if (name.length() == 0) {
name = null;
}
}
String host = uri.getHost();
if (host == null) {
host = "";
try {
/*
* With 2396 URI handling, forms such as 'rmi://host:bar'
* or 'rmi://:<port>' are parsed into a registry based
* authority. We only want to allow server based naming
* authorities.
*/
uri.parseServerAuthority();
} catch (URISyntaxException use) {
// Check if the authority is of form ':<port>'
String authority = uri.getAuthority();
if (authority != null && authority.startsWith(":")) {
// Convert the authority to 'localhost:<port>' form
authority = "localhost" + authority;
try {
uri = new URI(null, authority, null, null, null);
// Make sure it now parses to a valid server based
// naming authority
uri.parseServerAuthority();
} catch (URISyntaxException use2) {
throw new
MalformedURLException("invalid authority: " + str);
}
} else {
throw new
MalformedURLException("invalid authority: " + str);
}
}
}
int port = uri.getPort();
if (port == -1) {
port = Registry.REGISTRY_PORT;
}
return new ParsedNamingURL(host, port, name);
}
/**
* Simple class to enable multiple URL return values.
*/
private static class ParsedNamingURL {
String host;
int port;
String name;
ParsedNamingURL(String host, int port, String name) {
this.host = host;
this.port = port;
this.name = name;
}
}
}
@@ -0,0 +1,66 @@
/**
* Copyright Terracotta, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.eactive.eai.common.session;
import net.sf.ehcache.distribution.CacheManagerPeerProvider;
import net.sf.ehcache.distribution.RMICacheManagerPeerProvider;
import net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory;
import net.sf.ehcache.util.PropertyUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Properties;
import java.util.StringTokenizer;
/**
* RMICacheManagerPeerProviderFactory 상속받아서
* CustomManualRMICacheManagerPeerProvider 로 벼경
*
*
* @author jun's
* @version
*/
public class TimeoutRMICacheManagerPeerProviderFactory extends RMICacheManagerPeerProviderFactory {
private static final Logger LOG = LoggerFactory.getLogger(TimeoutRMICacheManagerPeerProviderFactory.class.getName());
private static final String RMI_URLS = "rmiUrls";
private static final String URL_DELIMITER = "|";
/**
* peerDiscovery=manual, rmiUrls=//hostname:port/cacheName //hostname:port/cacheName //hostname:port/cacheName
*/
protected CacheManagerPeerProvider createManuallyConfiguredCachePeerProvider(Properties properties) {
String rmiUrls = PropertyUtil.extractAndLogProperty(RMI_URLS, properties);
if (rmiUrls == null || rmiUrls.length() == 0) {
LOG.info("Starting manual peer provider with empty list of peers. " +
"No replication will occur unless peers are added.");
rmiUrls = "";
}
rmiUrls = rmiUrls.trim();
StringTokenizer stringTokenizer = new StringTokenizer(rmiUrls, URL_DELIMITER);
RMICacheManagerPeerProvider rmiPeerProvider = new TimeoutManualRMICacheManagerPeerProvider();
while (stringTokenizer.hasMoreTokens()) {
String rmiUrl = stringTokenizer.nextToken();
rmiUrl = rmiUrl.trim();
rmiPeerProvider.registerPeer(rmiUrl);
LOG.debug("Registering peer {}", rmiUrl);
}
return rmiPeerProvider;
}
}
@@ -0,0 +1,40 @@
package com.eactive.eai.common.session;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.rmi.server.RMISocketFactory;
/**
* 1. 기능 : RMISocketFactory를 상속받아서
* connection Timeout 과 read Timeout 을 설정할수 있도록 구현
* 2. 처리 개요 :
* 3. 주의사항
*
* @author :
* @version : v 1.0.0
* @see : 관련 기능을 참조
* @since :
* :
*/
public class TimeoutRMISocketFactory extends RMISocketFactory
{
private int connectionTimeout;
private int readTimeout;
public TimeoutRMISocketFactory(int connectionTimeout,int readTimeout){
super();
this.connectionTimeout = connectionTimeout;
this.readTimeout =readTimeout;
}
public Socket createSocket(String host,int port) throws IOException{
Socket socket = new Socket();
socket.setSoTimeout(this.readTimeout);
socket.setSoLinger(false, 0);
socket.connect(new InetSocketAddress(host,port), this.connectionTimeout);
return socket;
}
public ServerSocket createServerSocket(int port) throws IOException{
return new ServerSocket(port);
}
}