Files
elink-online-common/src/main/java/com/eactive/eai/message/parser/FlatReader.java
T
2025-12-09 13:46:56 +09:00

315 lines
12 KiB
Java

package com.eactive.eai.message.parser;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.eactive.eai.message.EncodingVar;
import com.eactive.eai.message.StandardDataType;
import com.eactive.eai.message.StandardItem;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.StandardType;
public class FlatReader implements StandardReader {
static Logger logger = LoggerFactory.getLogger(FlatReader.class);
private char FIELD_SEPARATOR = '.';
private boolean ZERO_BASE_INDEX = true;
public FlatReader() {
}
public StandardMessage parse(StandardMessage message, Object flatObject) throws Exception {
ArrayList<StandardItem> list = message.toList();
for(int i=0; i<list.size(); i++) {
StandardItem item = list.get(i);
logger.debug("{} Level={} Name={}", i, item.getLevel(), item.getName());
}
byte[] srcbytes = null;
String encoding = EncodingVar.flatEncoding;
if (flatObject instanceof String) {
try {
logger.debug("Encoding : {}", encoding);
srcbytes = ((String) flatObject).getBytes(encoding);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
srcbytes = ((String) flatObject).getBytes();
}
} else {
srcbytes = (byte[]) flatObject;
}
// make item map(path, value)
LinkedHashMap<String, String> itemMap = new LinkedHashMap<String, String>();
message.setReadPosition(0);
traverse(message, message, srcbytes, null, itemMap);
int remain = srcbytes.length - message.getReadPosition();
if(remain > 0) {
throw new Exception("flat message parsing error(overflow) remain size="+remain);
}
message.setBizDataCharset(encoding);
logger.debug("setBizDataCharset : {}", encoding);
// for(String key:itemMap.keySet()) {
// logger.debug("~ itemMap : {} => {}", key, itemMap.get(key) );
// }
return message;
}
private void traverse(StandardMessage message, StandardItem currentItem, byte[] srcbytes, String parentName
, LinkedHashMap<String, String> itemMap){
String fieldName = null;
ArrayList<StandardItem> childList = null;
StandardItem item = null;
int type = currentItem.getType();
int start = message.getReadPosition();
fieldName = genPath(parentName, currentItem.getName());
logger.debug("<-> CALL path = " + fieldName);
switch(type) {
case StandardType.MESSAGE:
childList = currentItem.getChildsList();
for(int i=0; i<childList.size(); i++) {
item = childList.get(i);
logger.debug("@MESSAGE path = {}, start={}, length={}, value=[{}]", fieldName, start, item.getLength(), item.getValue());
traverse(message, item, srcbytes, null, itemMap);
}
break;
case StandardType.FIELD:
item = currentItem; //message.findItem(fieldName, FIELD_SEPARATOR, ZERO_BASE_INDEX, true);
//아래로직은 BIZDATA 에서 처리 하기 때문에 삭제
// if(item.getDataType() == StandardDataType.ZZ_STRING) {
//// start = start - item.getLength();
// logger.debug("@FIELD path = {}, start={}, length={}, ZZ check start {}", fieldName, start, item.getLength(), item.getValue(), start);
// // cut bizData
// try {
// message.cutBizData(item.getLength());
// } catch (Exception e) {
// logger.error("@FIELD path = {}, start={}, length={}, cutBizData Failed", fieldName, start, item.getLength(), e);
// }
// }
byte[] value = cut(fieldName, srcbytes, start, item.getLength());
item.setBytesValue(value, EncodingVar.flatEncoding);
itemMap.put(fieldName, item.getValue());
logger.debug("@FIELD path = {}, start={}, length={}, value=[{}]", fieldName, start, item.getLength(), item.getValue());
start = start + item.getLength();
message.setReadPosition(start);
break;
case StandardType.GROUP:
logger.debug("@GROUP name={}, getLength={}, getRefPath={}, getRefValue=[{}]"
, currentItem.getName(), currentItem.getLength(), currentItem.getRefPath(), currentItem.getRefValue());
if( currentItem.getSize() == 0
&& StringUtils.isNotBlank(currentItem.getRefPath())
&& StringUtils.isNotBlank(currentItem.getRefValue()) ) {
//2024.08.07 아래추가로직은 Group 하위의 field 값에 따라서
//파싱을 해야 될경우 추가
String refItemValue ="";
if (currentItem.getRefPath().startsWith(fieldName)){
refItemValue = getRefItemValue(currentItem.getRefPath(), fieldName, srcbytes, currentItem, start);
}else{
refItemValue = itemMap.get(currentItem.getRefPath());
}
logger.debug("@GROUP name={}, getRefPath={}, refItemValue=[{}], getRefValue=[{}]"
, currentItem.getName(), currentItem.getRefPath(), refItemValue, currentItem.getRefValue());
if(refItemValue != null) refItemValue = refItemValue.trim();
/*
* 값의 경우의수 NR,ER,""(blank)
* ER이 아닐경우 표현하고 싶어서 ! 를 추가했음
* 원칙으로는 NR을 넣었을경우에는 NR 이 있을경우에만 해당됨
* !ER일경우에는 blank와 NR일 경우에 해당됨
*/
String refValue = currentItem.getRefValue();
if (refValue.startsWith("!")) { // 느낌표가 들어가면 다음에 나오는게 아닌경우
refValue = refValue.substring(1);
if (refValue.equals(refItemValue)) {
logger.warn("@GROUP name={} SKIPPED.", currentItem.getName());
currentItem.setHidden(true);
break;
} else {
currentItem.setHidden(false);
}
} else {
if (!currentItem.getRefValue().equals(refItemValue)) {
logger.warn("@GROUP name={} SKIPPED.", currentItem.getName());
currentItem.setHidden(true);
break;
} else {
currentItem.setHidden(false);
}
}
}
childList = currentItem.getChildsList();
for(int i=0; i<childList.size(); i++) {
item = childList.get(i);
logger.debug("@GROUP item={}, path = {}, start={}, length={}, value=[{}]", item.getName(), fieldName, start, item.getLength(), item.getValue());
traverse(message, item, srcbytes, fieldName, itemMap);
}
if( currentItem.getSize() == 0) {
currentItem.setSize(1);
}
break;
case StandardType.GRID:
logger.debug("@GRID name={}, getLength={}, getRefPath={}, getRefValue=[{}]"
, currentItem.getName(), currentItem.getLength(), currentItem.getRefPath(), currentItem.getRefValue());
if( currentItem.getSize() == 0
&& (StringUtils.isNotBlank(currentItem.getRefPath())
|| StringUtils.isNotBlank(currentItem.getRefValue())) ) {
String refItemValue = "";
if (StringUtils.isNotBlank(currentItem.getRefPath())) {
refItemValue = itemMap.get(currentItem.getRefPath());
currentItem.setRefValue(refItemValue);
} else {
refItemValue = currentItem.getRefValue();
}
currentItem.setSize(NumberUtils.toInt(StringUtils.trim(refItemValue)));
logger.debug("@GRID name={}, getRefPath={}, refItemValue=[{}], getRefValue=[{}]"
, currentItem.getName(), currentItem.getRefPath(), refItemValue, currentItem.getRefValue());
if( !currentItem.getRefValue().equals(refItemValue) ) {
logger.warn("@GRID name={} SKIPPED.", currentItem.getName());
break;
}
}
int arraySize = currentItem.getSize();
for(int ai = 0; ai<arraySize; ai++) {
LinkedHashMap<String, StandardItem> map = currentItem.getArrayChilds(ai, true);
if(map == null) {
logger.warn("Array create failed item path = {}", fieldName +"[" + ai +"]");
continue;
}
childList = new ArrayList<StandardItem>(map.values());
for(int i=0; i<childList.size(); i++) {
item = childList.get(i);
logger.debug("@ARRAY parent path = {}, item={}, start={}, length={}, current value=[{}]", fieldName+"[" + ai +"]", item.getName(), start, item.getLength(), item.getValue());
traverse(message, item, srcbytes, fieldName +"[" + ai +"]", itemMap);
}
}
break;
case StandardType.FARRAY:
logger.debug("@FARRAY name={}, getLength={}, getRefPath={}, getRefValue=[{}]"
, currentItem.getName(), currentItem.getLength(), currentItem.getRefPath(), currentItem.getRefValue());
int farraySize = currentItem.getSize();
item = currentItem; //message.findItem(fieldName, FIELD_SEPARATOR, ZERO_BASE_INDEX, true);
for(int ai = 0; ai<farraySize; ai++) {
//아래로직은 BIZDATA 에서 처리 하기 때문에 삭제
// if(item.getDataType() == StandardDataType.ZZ_STRING) {
// start = start - item.getLength();
// logger.debug("@FARRAY path = {}, start={}, length={}, ZZ check start {}", fieldName, start, item.getLength(), item.getValue(), start);
// // cut bizData
// try {
// message.cutBizData(item.getLength());
// } catch (Exception e) {
// logger.error("@FARRAY path = {}, start={}, length={}, cutBizData Failed", fieldName, start, item.getLength(), e);
// }
// }
value = cut(fieldName, srcbytes, start, item.getLength());
item.addBytesValue(value);
itemMap.put(fieldName, item.getValue());
logger.debug("@FARRAY path = {}, start={}, length={}, value=[{}]", fieldName, start, item.getLength(), item.getValue());
start = start + item.getLength();
message.setReadPosition(start);
}
break;
case StandardType.BIZDATA:
// FIX-ME : how to calculate bzi data size ?
// current : bizData is last item in layout items (variable size)
item = message.findItem(fieldName, FIELD_SEPARATOR, ZERO_BASE_INDEX, true);
int bizDataSize = item.getLength();
int zzLength = 0;
String zzDataPath = message.getZzDataPath();
if(StringUtils.isNotEmpty(zzDataPath)) {
try {
StandardItem zzItem = message.findItem(zzDataPath);
if(zzItem != null) {
zzLength = zzItem.getLength();
}
}
catch(Exception ex) {
logger.warn("ZzData check error", ex);
}
}
if(bizDataSize == 0) {
bizDataSize = srcbytes.length - start - zzLength;
}
byte[] bizDataBytes = cut(fieldName, srcbytes, start, bizDataSize);
item.setBytesValue(bizDataBytes, EncodingVar.flatEncoding);
itemMap.put(fieldName, item.getValue());
logger.debug("@BIZDATA path = {}, start={}, length={}, value=[{}]", fieldName, start, item.getLength(), item.getValue());
start = start + bizDataSize;
message.setReadPosition(start);
break;
default:
break;
}
}
private String genPath(String parent, String nodeName) {
if(parent == null || parent.length() < 1) {
return nodeName;
}
return parent + FIELD_SEPARATOR + nodeName;
}
private static byte[] cut(String fieldName, byte[] srcBytes, int start, int length) {
if (srcBytes == null) {
return null;
}
if (srcBytes.length < (start+length)) {
StringBuffer sb = new StringBuffer();
sb.append("item="+ fieldName);
sb.append(", cut failed(underflow) - start index=" + start);
sb.append(", item length=" + length);
sb.append(", total size=" + srcBytes.length);
throw new RuntimeException(sb.toString());
}
byte[] result = new byte[length];
int end = start + length;
int p=0;
for (int i = start; i < end; i++) {
result[p] = srcBytes[i];
p++;
}
return result;
}
private String getRefItemValue(String orgRef, String fieldName, byte[] srcbytes , StandardItem currentItem ,int start ){
String currentFieldName = orgRef.replace(fieldName+".","");
ArrayList<StandardItem> childList = currentItem.getChildsList();
String refItemValue ="";
for(StandardItem item : childList) {
if (currentFieldName.indexOf(".") < 0) {
byte[] tempValue = null;
if (orgRef.equals(fieldName + "." + item.getName())) {
tempValue = cut(fieldName, srcbytes, start, item.getLength());
return new String(tempValue);
}else{
start = start + item.getLength();
}
} else {
return getRefItemValue(orgRef, fieldName+"."+item.getName(), srcbytes, item, start);
}
}
return refItemValue;
}
// public static void main(String[] args) {
// }
}