Files
elink-online-common/src/main/java/com/eactive/eai/message/manager/StandardMessageManager.java
T
curry772 ae6ed9b262 fix: DJBank 표준전문 대응 프레임워크 수정
- BaseFCProcess.setGUID(): nextGuidSeq 자동 호출 비활성화
  (guid_prgs_no 증가는 Coordinator에서 처리)
- DefaultProcess: 오류 응답 시 nextGuidSeq 자동 호출 비활성화
- RequestProcessor: GUID 조합(guid+seq) 로직 비활성화,
  logger.error에 exception 객체 추가
- StandardMessageManager: config 기본 경로 ./resources/ → ./ 수정

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 15:48:20 +09:00

451 lines
16 KiB
Java

package com.eactive.eai.message.manager;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.StringUtils;
import com.eactive.eai.common.exception.ExceptionUtil;
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.util.Logger;
import com.eactive.eai.message.EncodingVar;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.StandardMessageUtil;
import com.eactive.eai.message.filter.MessageFilter;
import com.eactive.eai.message.mapper.MessageMapper;
import com.eactive.eai.message.parser.StandardReader;
import com.eactive.eai.message.service.InterfaceMapper;
import com.eactive.eai.message.service.StandardMessageCoordinator;
public class StandardMessageManager implements Lifecycle {
static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
private static StandardMessageManager instance;
private boolean started;
private LifecycleSupport lifecycle = new LifecycleSupport(this);
/**
# standard-message-config.properties
# layout : StandardMessage layout definition
layout.file.type=CSV
layout.file.path=./resources/standard-layout.csv
# mapper : StandardMessage's fields getter/setter interface
mapper.class=com.eactive.eai.message.service.DefaultInterfaceMapper
mapper.definition=./resources/standard-message-mapping-config.properties
# reader : parsing input data to StandardMessage
reader.JSON=com.eactive.eai.message.parser.JsonReader
reader.XML=com.eactive.eai.message.parser.XmlReader
reader.FLAT=com.eactive.eai.message.parser.FlatReader
*/
public static String STANDARD_MESSAGE_CONFIG = "standard.message.config";
private String DEFAULT_CONFIG_PATH = "./standard-message-config.properties";
private String DEFAULT_CONFIG_FILE = "standard-message-config.properties";
private String LAYOUT_FILE_TYPE = "layout.file.type";
private String LAYOUT_FILE_PATH = "layout.file.path";
private String LAYOUT_FILTER = "layout.filter.FLAT";
private String MAPPER_CLASS = "mapper.class";
private String MAPPER_DEFINITION = "mapper.definition";
private String READER_PREFIX = "reader.";
private String ENCODE_FLAT = "encode.flat";
private String ENCODE_XML = "encode.xml";
private String ENCODE_JSON = "encode.json";
private String COORDINATOR_CLASS = "message.coordinator.class";
private String DEFAULT_COORDINATOR_CLASS = "com.eactive.eai.message.service.DefaultStandardMessageCoordinator";
private String REQUEST_PROCESSOR_CLASS = "requestProcessor.class";
private StandardMessage standardMessage = null;
private InterfaceMapper mapper;
private StandardMessageCoordinator messageCoordinator;
private ConcurrentHashMap<String, StandardReader> readerMap = null;
private Map<String, String> versionMap = new HashMap<>();;
private String VERSION_LAYOUT_NAME = "version.layout.name";
private String VERSION_LAYOUT_FILTER = "version.layout.filter.FLAT";
private String VERSION_MAPPER = "version.mapper";
private String VERSION_MAPPING_DEFINATION = "version.mapper.definition";
private MessageMapper versionMapper;
private StandardMessage versionMessage = null;
private String versionLayoutName = null;
public Map<String, String> getVersionMap() {
return versionMap;
}
public void setVersionMap(Map<String, String> versionMap) {
this.versionMap = versionMap;
}
public String getVersionLayoutName() {
return versionLayoutName;
}
public void setVersionLayoutName(String versionLayoutName) {
this.versionLayoutName = versionLayoutName;
}
public synchronized StandardMessage getVersionMessage() {
if(versionMessage == null) return null;
try {
return (StandardMessage) versionMessage.clone();
} catch (CloneNotSupportedException e) {
return SerializationUtils.clone(standardMessage);
}
}
private StandardMessageManager() {
readerMap = new ConcurrentHashMap<>();
}
public static StandardMessageManager getInstance() {
return LazyHolder.INSTANCE;
}
private static class LazyHolder {
private static final StandardMessageManager INSTANCE = new StandardMessageManager();
}
public void start() throws LifecycleException {
if (started)
throw new LifecycleException("RECEAICMM201");
lifecycle.fireLifecycleEvent(STARTING_EVENT, this);
try {
init();
} catch(Exception e) {
throw new LifecycleException(ExceptionUtil.getErrorCode(e,"RECEAICMM202"));
}
started = true;
lifecycle.fireLifecycleEvent(STARTED_EVENT, this);
}
public void stop() throws LifecycleException {
if (!started)
throw new LifecycleException("RECEAICMM203");
lifecycle.fireLifecycleEvent(STOPING_EVENT, this);
readerMap.clear();
readerMap = null;
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;
}
public synchronized StandardMessage getStandardMessage() {
try {
return (StandardMessage) standardMessage.clone();
} catch (CloneNotSupportedException e) {
return SerializationUtils.clone(standardMessage);
}
}
public MessageMapper getVersionMapper() {
return versionMapper;
}
public void setVersionMapper(MessageMapper versionMapper) {
this.versionMapper = versionMapper;
}
public InterfaceMapper getMapper() {
return mapper;
}
public void setMapper(InterfaceMapper mapper) {
this.mapper = mapper;
}
public StandardMessageCoordinator getMessageCoordinator() {
return messageCoordinator;
}
public void setMessageCoordinator(StandardMessageCoordinator messageCoordinator) {
this.messageCoordinator = messageCoordinator;
}
public synchronized void reload() throws Exception {
if(logger.isWarn()) {
logger.warn("StandardMessageManager] reload all started ...");
}
init();
if(logger.isWarn()) {
logger.warn("StandardMessageManager] reload all finished ...");
}
}
@SuppressWarnings("rawtypes")
private void initReaderFactory(Properties config) {
Class cl = null;
StandardReader reader = null;
Set<Object> keys = config.keySet();
for(Object key: keys) {
String keyStr = (String)key;
if(keyStr.startsWith(READER_PREFIX)) {
String name = keyStr.substring(READER_PREFIX.length());
String readerClassName = config.getProperty(keyStr);
try {
cl = Class.forName(readerClassName);
reader = (StandardReader)cl.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
if(logger.isWarn()) logger.warn(String.format("Invalid class path : %s %s", keyStr, readerClassName), e);
continue;
}
readerMap.put(name, reader);
if(logger.isWarn()) logger.warn(String.format("# Add reader : %s %s", keyStr, readerClassName));
}
}
}
public StandardReader getReader(String messageType) {
return readerMap.get(messageType);
}
@SuppressWarnings("rawtypes")
public void init() throws Exception {
try {
Properties config = loadConfigFile();
logger.debug(config.toString());
String encodeFlat = config.getProperty(ENCODE_FLAT, "euc-kr");
String encodeXml = config.getProperty(ENCODE_XML, "utf-8");
String encodeJson = config.getProperty(ENCODE_JSON, encodeXml);
String requestProcessorClass = config.getProperty(REQUEST_PROCESSOR_CLASS);
if(logger.isDebug()) {
logger.debug( "{} : {}", ENCODE_FLAT, encodeFlat );
logger.debug( "{} : {}", ENCODE_XML, encodeXml );
logger.debug( "{} : {}", ENCODE_JSON, encodeJson );
logger.debug( "{} : {}", REQUEST_PROCESSOR_CLASS, requestProcessorClass );
}
EncodingVar.flatEncoding = encodeFlat;
EncodingVar.xmlEncoding = encodeXml;
EncodingVar.jsonEncoding = encodeJson;
StandardMessageUtil.requestProcessorClass = requestProcessorClass;
String layoutFileType = config.getProperty(LAYOUT_FILE_TYPE, "CSV");
String path = config.getProperty(LAYOUT_FILE_PATH);
if(logger.isDebug()) {
// logger.debug( String.format("%s : %s", LAYOUT_FILE_TYPE, layoutFileType) );
// logger.debug( String.format("%s : %s", LAYOUT_FILE_PATH, path) );
logger.debug( "{} : {}", LAYOUT_FILE_TYPE, layoutFileType );
logger.debug( "{} : {}", LAYOUT_FILE_PATH, path );
}
if("CSV".contentEquals(layoutFileType.toUpperCase())) {
standardMessage = StandardMessageUtil.generateMessageFromCsvFile(path);
} else if(StringUtils.startsWithIgnoreCase(layoutFileType, "DB")) {
String layout = StringUtils.substring(layoutFileType, 3);
standardMessage = StandardMessageUtil.generateMessageFromDb(StringUtils.trimToNull(layout));
} else {
standardMessage = StandardMessageUtil.generateMessageFromCsvFile(path);
}
if(standardMessage != null) {
standardMessage.setReadPosition(0);
}
String flatFilterClass = config.getProperty(LAYOUT_FILTER);
logger.debug("{} : {}", LAYOUT_FILTER, flatFilterClass);
String versionFlatFilterClass = config.getProperty(VERSION_LAYOUT_FILTER);
logger.debug("{} : {}", VERSION_LAYOUT_FILTER, versionFlatFilterClass);
if(StringUtils.isNotBlank(flatFilterClass)) {
try {
Class cl = Class.forName(flatFilterClass);
MessageFilter flatFilter = (MessageFilter)cl.newInstance();
standardMessage.setFlatFilter(flatFilter);
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
if(logger.isWarn()) logger.warn(String.format("configure %s : %s", LAYOUT_FILTER, flatFilterClass), e);
}
}
String coordinatorClass = config.getProperty(COORDINATOR_CLASS, DEFAULT_COORDINATOR_CLASS);
logger.debug("{} : {}", COORDINATOR_CLASS, coordinatorClass);
try {
Class cl = Class.forName(coordinatorClass);
this.messageCoordinator = (StandardMessageCoordinator) cl.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
if (logger.isWarn())
logger.warn(String.format("configure %s : %s", COORDINATOR_CLASS,
config.getProperty(COORDINATOR_CLASS)), e);
}
String mapperClass = config.getProperty(MAPPER_CLASS);
String mapperFilePath = config.getProperty(MAPPER_DEFINITION);
if(logger.isDebug()) logger.debug( String.format("%s : %s", MAPPER_CLASS, mapperClass) );
if(logger.isDebug()) logger.debug( String.format("%s : %s", MAPPER_DEFINITION, mapperFilePath) );
if(mapperClass == null) {
throw new Exception("StandardMessageManager | config error, not found config : " + MAPPER_CLASS);
}
if(mapperFilePath == null) {
throw new Exception("StandardMessageManager | config error, not found config : " + MAPPER_DEFINITION);
}
initReaderFactory(config);
Class cl = null;
try {
cl = Class.forName(mapperClass);
mapper = (InterfaceMapper)cl.newInstance();
Properties mapperMapPropties = loadConfigFileProperties(mapperFilePath);
HashMap<String, String> map = propertyToMap(mapperMapPropties);
mapper.initPathMap(map);
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
return;
}
if(logger.isDebug()) logger.debug("mapperClass : {}", mapper.getClass().getCanonicalName());
String versionMapperClass = config.getProperty(VERSION_MAPPER);
if(StringUtils.isEmpty(versionMapperClass)) {
versionMapperClass = "com.eactive.eai.message.mapper.DefaultMessageMapper";
}
if(logger.isDebug()) logger.debug("version.mapper : {}", versionMapperClass);
try {
Class clazz = Class.forName(versionMapperClass);
versionMapper = (MessageMapper)clazz.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
return;
}
if(logger.isDebug()) logger.debug("version.mapper class : {}", versionMapper.getClass().getCanonicalName());
String versionMapFilePath = config.getProperty(VERSION_MAPPING_DEFINATION);
if(logger.isDebug()) logger.debug( String.format("%s : %s", VERSION_MAPPING_DEFINATION, versionMapFilePath) );
if(versionMapFilePath != null) {
Properties versionMapPropties = loadConfigFileProperties(versionMapFilePath);
versionMap = propertyToMap(versionMapPropties);
}
if(logger.isDebug()) logger.debug("versionMap size ="+ versionMap.size() );
versionLayoutName = config.getProperty(VERSION_LAYOUT_NAME);
if(logger.isDebug()) logger.debug( String.format("%s : %s", VERSION_LAYOUT_NAME, versionLayoutName) );
if(versionLayoutName != null) {
versionMessage = StandardMessageUtil.generateMessageFromDb(versionLayoutName);
versionMessage.setReadPosition(0);
if(StringUtils.isNotBlank(versionFlatFilterClass)) {
try {
Class vcl = Class.forName(versionFlatFilterClass);
MessageFilter versionFlatFilter = (MessageFilter)vcl.newInstance();
versionMessage.setFlatFilter(versionFlatFilter);
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
if(logger.isWarn()) logger.warn(String.format("configure %s : %s", VERSION_LAYOUT_FILTER, versionFlatFilterClass), e);
}
}
}
}
catch(Exception ex) {
ex.printStackTrace();
logger.error("init failed", ex);
}
}
private HashMap<String, String> propertyToMap(Properties prop) {
HashMap<String, String> retMap = new HashMap<>();
for (Map.Entry<Object, Object> entry : prop.entrySet()) {
retMap.put(String.valueOf(entry.getKey()).trim(), String.valueOf(entry.getValue()).trim());
}
return retMap;
}
private Properties loadConfigFile() throws Exception {
String configFile = getConfigFile();
return loadConfigFileProperties(configFile);
}
private Properties loadConfigFileProperties(String configFile) throws Exception {
try {
return loadFileProperties(configFile);
}
catch(Exception e) {
// logger.warn("StandardMessageManager | loadFileProperties failed. - " + configFile, e);
logger.warn("StandardMessageManager | loadFileProperties failed. - " + configFile +", " +e.getMessage());
}
// try classpath file
return loadClassPathProperties(configFile);
}
private Properties loadFileProperties(String filePath) throws Exception {
logger.debug("configFile : ", filePath);
Properties p = new Properties();
try(InputStream in = new FileInputStream(filePath)) {
p.load(in);
return p;
} catch(Exception e) {
throw new Exception("StandardMessageManager | Cannot load config file. - " + filePath, e);
}
}
private Properties loadClassPathProperties(String filePath) throws Exception {
Properties p = new Properties();
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
logger.warn("StandardMessageManager | ClassLoader : load. - "+ filePath);
try( InputStream in = classLoader.getResourceAsStream(filePath) ) {
p.load(in);
return p;
} catch(Exception e) {
if(logger.isWarn()) {
// logger.warn("StandardMessageManager | ClassLoader : Cannot load config file. - " + filePath, e);
logger.warn("StandardMessageManager | ClassLoader : Cannot load config file. - " + filePath +", " +e.getMessage());
}
}
logger.warn("StandardMessageManager | ClassLoader : load default - "+ DEFAULT_CONFIG_FILE);
try( InputStream in = classLoader.getResourceAsStream(DEFAULT_CONFIG_FILE) ) {
p.load(in);
logger.warn("StandardMessageManager | ClassLoader : load default success - "+ DEFAULT_CONFIG_FILE);
return p;
} catch(Exception e) {
logger.error("StandardMessageManager | ClassLoader : Cannot load default config file. - " + DEFAULT_CONFIG_FILE, e);
throw new Exception("StandardMessageManager | ClassLoader : Cannot load default config file. - " + DEFAULT_CONFIG_FILE, e);
}
}
private String getConfigFile() {
String configFilePath = System.getProperty(STANDARD_MESSAGE_CONFIG);
if (StringUtils.isEmpty(configFilePath)) {
return DEFAULT_CONFIG_PATH;
} else {
return configFilePath;
}
}
}