ae6ed9b262
- 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>
451 lines
16 KiB
Java
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;
|
|
}
|
|
}
|
|
}
|