package com.eactive.eai.message; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashMap; import com.eactive.eai.common.util.StringUtil; import com.eactive.eai.data.entity.onl.stdmessage.StandardMessageLayoutItem; import com.eactive.eai.transformer.util.ByteUtil; import org.apache.commons.lang3.SerializationUtils; import org.apache.commons.lang3.StringUtils; import org.json.simple.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class StandardItem implements Serializable, Cloneable { private static final long serialVersionUID = -4430144517271735912L; static Logger logger = LoggerFactory.getLogger(StandardItem.class); LinkedHashMap childs = new LinkedHashMap(); ArrayList> list = new ArrayList>(); ArrayList values = new ArrayList(); // FIX-ME : check encoding // String <-> byte[] charset // private static String encode = "ms949"; //"euc-kr"; // private static String encodeXml = "utf-8"; // private static String encodeJson = "utf-8"; public static int ITEM_COUNT = 11; String name; int level; // 0 : root ~ n int type; // 1: Message, 2: Field, 3:Group, 4 : Grid, 5 : Field Array, 9 : BIZ DATA int size; // array size int fieldType; // 1: ELEMENT, 2: ATTRIBUTE, int length; int dataType; // 1: String, 2: Number, 11: ZZ String, 12: Length Number String refPath; String refValue; String value; String desc = ""; boolean isHidden =false; byte[] bytesValue = null; // configuration options // if data is null, convert to empty-space private static boolean NULL_TO_SPACE = true; // if add json root item with message name private static boolean ADD_JSON_ROOT = false; static { resetSystemParameters(); } public static void resetSystemParameters() { try { NULL_TO_SPACE = Boolean.parseBoolean( System.getProperty("standard.message.nulltospace", "true") ); } catch(Exception ex) { ; } try { ADD_JSON_ROOT = Boolean.parseBoolean( System.getProperty("standard.message.addjsonroot", "false") ); } catch(Exception ex) { ; } } public StandardItem() { } public StandardItem(String name, int level, int type, int size, int fieldType, int length, int dataType, String refPath, String refValue, String value, String desc) { super(); initValues(name, level, type, size, fieldType, length, dataType, refPath, refValue, value, desc); } public StandardItem(String name, int level, int type, int size, int length, int dataType, String value, String desc) { super(); initValues(name, level, type, size, 0, length, dataType, null, null, value, desc); } public StandardItem(String name, int level, int type, int size, int length, int dataType, String value) { super(); initValues(name, level, type, size, 0, length, dataType, null, null, value, null); } public StandardItem(String name, int level, int type, int length, int dataType, String value, String desc) { super(); initValues(name, level, type, 1, 0, length, dataType, null, null, value, desc); } public StandardItem(String name, int level, int type, int length, int dataType, String value) { super(); initValues(name, level, type, 1, 0, length, dataType, null, null, value, null); } public void initValues(String name, int level, int type, int size, int fieldType, int length, int dataType, String refPath, String refValue, String value, String desc) { this.name = name; this.level = level; this.type = type; this.size = size; this.fieldType = fieldType; this.length = length; this.dataType = dataType; this.refPath = refPath; this.refValue = refValue; setValue(value); if(desc != null) this.desc = desc; } public StandardItem(String[] values) throws Exception { if(values == null || values.length < ITEM_COUNT-1) { throw new Exception("invalid StandardItem defination values : " + (values==null? "":values.length)); } this.name = values[0].trim(); this.level = Integer.parseInt(values[1].trim()); this.type = Integer.parseInt(values[2].trim()); this.size = Integer.parseInt(values[3].trim());; this.fieldType = Integer.parseInt(values[4].trim()); this.length = Integer.parseInt(values[5].trim());; this.dataType = Integer.parseInt(values[6].trim()); this.refPath = values[7].trim(); this.refValue = values[8].trim(); setValue(values[9]); if(values.length == ITEM_COUNT) { setDesc(values[10].trim()); } else { setDesc(values[0].trim()); } } public StandardItem(StandardMessageLayoutItem entityItem) { this.name = entityItem.getItemName(); this.level = entityItem.getItemLevel(); this.type = entityItem.getItemType(); this.size = entityItem.getArraySize(); this.fieldType = entityItem.getFieldType(); this.length = entityItem.getDataLength(); this.dataType = entityItem.getDataType(); this.refPath = entityItem.getRefFieldPath(); this.refValue = entityItem.getRefValue(); setValue(entityItem.getDefaultValue()); setDesc(entityItem.getItemDesc()); } public void addItem (StandardItem item) { childs.put(item.getName(), item); } public void addArrayItem(int index, StandardItem item) { if( !childs.containsKey(item.getName()) ) { childs.put(item.getName(), item); } // add last if(list.size() == index) { LinkedHashMap items = new LinkedHashMap(); items.put(item.getName(), item); list.add(items); } else if(list.size() > index) { list.get(index).put(item.getName(), item); } else { logger.debug("index too big : index={} / array size={}", index, list.size()); } } public void addArray(LinkedHashMap items) { list.add(items); } public LinkedHashMap getArrayChilds(int index, boolean createNew) { if(index == list.size()) { // logger.debug("@@ add cloned childs in array item={}, index={}", this.name, index); if(createNew) { list.add((LinkedHashMap)(SerializationUtils.clone(childs)) ); } else { return null; } } else if(index > list.size()) { return null; } return list.get(index); } public LinkedHashMap getChilds() { return childs; } public ArrayList getChildsList() { ArrayList childList = new ArrayList(childs.values()); return childList; } public void setChilds(LinkedHashMap childs) { this.childs = childs; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getLevel() { return level; } public void setLevel(int level) { this.level = level; } public int getType() { return type; } public void setType(int type) { this.type = type; } public int getFieldType() { return fieldType; } public void setFieldType(int fieldType) { this.fieldType = fieldType; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public int getLength() { return length; } public void setLength(int length) { this.length = length; } public int getDataType() { return dataType; } public void setDataType(int dataType) { this.dataType = dataType; } public String getRefPath() { return refPath; } public void setRefPath(String refPath) { this.refPath = refPath; } public String getRefValue() { return refValue; } public void setRefValue(String refValue) { this.refValue = refValue; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public String getValue() { return value; } public boolean isHidden() { return isHidden; } public void setHidden(boolean isHidden) { this.isHidden = isHidden; } protected String toTypeValue(String svalue) { if(svalue == null) return svalue; if(dataType == StandardDataType.STRING || dataType == StandardDataType.ZZ_STRING) { return svalue; } else { char[] charValues = svalue.trim().toCharArray(); int i = 0; for(; i< charValues.length; i++) { if(charValues[i] == '0' || charValues[i] == ' ') { continue; } break; } return new String(charValues, i, (charValues.length - i)); } } public void setValue(String value) { this.value = toTypeValue(value); this.bytesValue = null; //value와 bytesValue의 불일치 때문 jun's 20231101 } public void addValue(String value) { values.add(toTypeValue(value)); } public void addBytesValue(byte[] bytesValue) { // this.bytesValue = bytesValue; String svalue = null; try { String encoding = EncodingVar.flatEncoding; // logger.debug("Encoding : {}", encoding ); svalue = new String(bytesValue, encoding); } catch (UnsupportedEncodingException e) { svalue = new String(bytesValue); } addValue(toTypeValue(svalue)); } // public byte[] getBytesValue() { // if(bytesValue != null) { // return bytesValue; // } // else { // try { // String encoding = EncodingVar.flatEncoding; //// logger.debug("Encoding : {}", encoding ); // this.bytesValue = value.getBytes(encoding); // } catch (UnsupportedEncodingException e) { // this.bytesValue = value.getBytes(); // } // return bytesValue; // } // } public byte[] getBytesValue(String charset) { if (bytesValue == null || bytesValue.length == 0) { if(value == null) return new byte[0]; try { // logger.debug("Encoding : {}", charset ); this.bytesValue = value.getBytes(charset); } catch (UnsupportedEncodingException e) { this.bytesValue = value.getBytes(); } return bytesValue; } else { return bytesValue; } } public void setBytesValue(byte[] bytesValue) { this.bytesValue = bytesValue; } public void setBytesValue(byte[] bytesValue, String charset) { try { logger.debug("charset : {}", charset ); this.value = toTypeValue(new String(bytesValue, charset)); } catch (UnsupportedEncodingException e) { this.value = toTypeValue(new String(bytesValue)); } } protected String getLevelIndent() { StringBuilder sb = new StringBuilder(); for(int i=0; i 0) { for(int i=0; i keyIter = null;; switch(getType()) { case StandardType.MESSAGE : keyIter = childs.keySet().iterator(); while(keyIter.hasNext()) { String key = keyIter.next(); StandardItem item = childs.get(key); sb.append("\n").append(item.toString()); } break; // case StandardType.FIELD : // break; case StandardType.GROUP : if (isHidden) break; keyIter = childs.keySet().iterator(); while(keyIter.hasNext()) { String key = keyIter.next(); StandardItem item = childs.get(key); sb.append("\n").append(item.toString()); } break; case StandardType.GRID : if (isHidden) break; for(int p=0; p group = list.get(p); keyIter = group.keySet().iterator(); while(keyIter.hasNext()) { String key = keyIter.next(); StandardItem item = group.get(key); sb.append("\n").append(item.toString()); } } break; // case StandardType.FARRAY : // break; // case StandardType.BIZDATA : // break; default : break; } return sb.toString(); } public String toCSVString() { StringBuilder sb = new StringBuilder(); if(level == 0) { sb.append("#name,level,type,size,fieldType,length,dataType,refPath,refValue,value,desc\n"); } sb.append(name); sb.append(","); sb.append(level); sb.append(","); sb.append(type); sb.append(","); sb.append(size); sb.append(","); sb.append(fieldType); sb.append(","); sb.append(length); sb.append(","); sb.append(dataType); sb.append(","); sb.append(refPath); sb.append(","); sb.append(refValue); sb.append(","); sb.append(value); sb.append(","); sb.append(desc); sb.append("\n"); Iterator keyIter = childs.keySet().iterator(); while(keyIter.hasNext()) { String key = keyIter.next(); StandardItem item = childs.get(key); sb.append(item.toCSVString()); } return sb.toString(); } public ArrayList toList() { ArrayList list = new ArrayList(); ArrayList childList = null; switch(getType()) { case StandardType.MESSAGE : list.add(this); childList = new ArrayList(childs.values()); for(int i=0; i(childs.values()); for(int i=0; i map = getArrayChilds(ai, false); childList = new ArrayList(map.values()); for(int i=0; i toLogList() { return toLogList(false); } public ArrayList toLogList(boolean withBizData) { ArrayList list = new ArrayList(); ArrayList childList = null; switch(getType()) { case StandardType.MESSAGE : // list.add(toLogItem(this)); childList = new ArrayList(childs.values()); for(int i=0; i(childs.values()); for(int i=0; i map = getArrayChilds(ai, withBizData); childList = new ArrayList(map.values()); for(int i=0; i toLogFlatList() { return toLogFlatList(false); } public ArrayList toLogFlatList(boolean withBizData) { ArrayList list = new ArrayList(); ArrayList childList = null; switch (getType()) { case StandardType.MESSAGE: childList = new ArrayList(childs.values()); for (int i = 0; i < childList.size(); i++) { list.addAll(childList.get(i).toLogFlatList(withBizData)); } break; case StandardType.FIELD: list.add(toLogFlatItem(this)); break; case StandardType.GROUP: if (isHidden) break; list.add(toLogFlatItem(this)); childList = new ArrayList(childs.values()); for (int i = 0; i < childList.size(); i++) { list.addAll(childList.get(i).toLogFlatList(withBizData)); } break; case StandardType.GRID: if (isHidden) break; list.add(toLogFlatItem(this)); int arraySize = getSize(); for (int ai = 0; ai < arraySize; ai++) { LinkedHashMap map = getArrayChilds(ai, withBizData); childList = new ArrayList(map.values()); for (int i = 0; i < childList.size(); i++) { list.addAll(childList.get(i).toLogFlatList(withBizData)); } } break; case StandardType.FARRAY: list.add(toLogFlatItem(this)); break; case StandardType.BIZDATA: if (withBizData) list.add(toLogFlatItem(this)); break; default: break; } return list; } protected String toJsonValue() { return toJsonValue(this.value); } protected String toJsonValue(String svalue) { if(dataType == StandardDataType.STRING || dataType == StandardDataType.ZZ_STRING) { if(svalue == null) { if(NULL_TO_SPACE) return "\"\""; else return null; } return "\"" + JSONObject.escape(svalue) + "\""; } else { if(StringUtils.isEmpty(svalue)) { return "0"; } else { return JSONObject.escape(svalue) ; } } } public String toJson() { return toJson(false, true); } public String toPrettyJson() { return toJson(true, true); } public String toJson(boolean showPretty, boolean withBizData) { StringBuilder sb = new StringBuilder(); Iterator keyIter = null; switch(getType()) { case StandardType.MESSAGE : sb.append("{"); // if root name add if(ADD_JSON_ROOT) sb.append("\"").append( name ).append("\"").append(":{"); // if(showPretty) sb.append("\n"); keyIter = childs.keySet().iterator(); int i=0; String part = null; while(keyIter.hasNext()) { String key = keyIter.next(); StandardItem item = childs.get(key); part = item.toJson(showPretty, withBizData); if(StringUtils.isNotEmpty(part)) { if(i>0) sb.append(","); if(showPretty) sb.append("\n"); sb.append(part); i++; } } if(ADD_JSON_ROOT) sb.append("}"); if(showPretty) sb.append("\n"); sb.append("}"); break; case StandardType.FIELD : if(StringUtils.isEmpty(this.value)) break; if(showPretty) sb.append(getLevelIndent()); sb.append("\"").append(name).append("\":").append(toJsonValue()); break; case StandardType.GROUP : // skip variable group if( getSize() == 0) { break; } if (isHidden) break; if(showPretty) sb.append(getLevelIndent()); sb.append("\"").append(name).append("\":{"); keyIter = childs.keySet().iterator(); int g=0; while(keyIter.hasNext()) { String key = keyIter.next(); StandardItem item = childs.get(key); part = item.toJson(showPretty, withBizData); if(StringUtils.isNotEmpty(part)) { if(g>0) sb.append(","); if(showPretty) sb.append("\n"); sb.append(part); g++; } } if(showPretty) { sb.append("\n"); sb.append(getLevelIndent()); } sb.append("}"); break; case StandardType.GRID : if(showPretty) { sb.append(getLevelIndent()); } if (isHidden) break; sb.append("\"").append(name).append("\":["); // if(showPretty) sb.append("\n"); for(int p=0; p group = list.get(p); keyIter = group.keySet().iterator(); int ai=0; if(showPretty) { sb.append("\n"); sb.append(getLevelIndent()); } if(p>0) sb.append(","); sb.append("{"); while(keyIter.hasNext()) { String key = keyIter.next(); StandardItem item = group.get(key); String itemPart = item.toJson(showPretty, withBizData); if(StringUtils.isNotEmpty(itemPart)) { if(ai>0) sb.append(","); if(showPretty) sb.append("\n"); sb.append(itemPart); ai++; } } if(showPretty) { sb.append("\n"); sb.append(getLevelIndent()).append("}"); } else { sb.append("}"); } } // if(showPretty) { // sb.append("\n"); // sb.append(getLevelIndent()); // } sb.append("]"); break; case StandardType.FARRAY : if(showPretty) { sb.append(getLevelIndent()); } sb.append("\"").append(name).append("\":["); // if(showPretty) sb.append("\n"); for(int p=0; p0) sb.append(","); sb.append(toJsonValue(values.get(p))); } // if(showPretty) { // sb.append("\n"); // sb.append(getLevelIndent()); // } sb.append("]"); break; case StandardType.BIZDATA : if(withBizData) { if(showPretty) sb.append(getLevelIndent()); sb.append("\"").append(name).append("\":"); if(StringUtils.isEmpty(getValue())) { // sb.append(toJsonValue(null)); sb.append("{}"); } else { // 업무데이터가 Json인지 확인 String jsonString = getValue(); if(jsonString.startsWith("{") || jsonString.startsWith("[")) {//배열로 시작하는게 있어서 sb.append(jsonString); } else { sb.append(toJsonValue()); } } } else { return null; } break; default : break; } return sb.toString(); } private String toStartTag(String nodeName) { StringBuilder sb = new StringBuilder(); sb.append("<").append(nodeName).append(">"); return sb.toString(); } private String toEndTag(String nodeName) { StringBuilder sb = new StringBuilder(); sb.append(""); return sb.toString(); } protected String toXmlValue() { return value; } public String toXML() { String encoding = EncodingVar.xmlEncoding; // logger.debug("Encoding : {}", encoding ); return toXML(encoding, false); } public String toPrettyXML() { String encoding = EncodingVar.xmlEncoding; // logger.debug("Encoding : {}", encoding ); return toXML(encoding, true); } // FIX-ME : Attribute와 Element가 혼합된 Group/Array는 현재 처리 불가함. // XML의 Attribute Group일 경우 Group과 Item의 FieldType은 모두 1 로 설정되어야 함. // 향후 XMLParser로 생성하는 방안은 고려해 봐야 함. public String toXML(String encode, boolean showPretty) { StringBuilder sb = new StringBuilder(); Iterator keyIter = null; switch(getType()) { case StandardType.MESSAGE : sb.append(""); if(showPretty) sb.append("\n"); sb.append(toStartTag(name)); keyIter = childs.keySet().iterator(); while(keyIter.hasNext()) { String key = keyIter.next(); StandardItem item = childs.get(key); sb.append(item.toXML(encode, showPretty)); } if(showPretty) sb.append("\n"); sb.append(toEndTag(name)); break; case StandardType.FIELD : if(fieldType == StandardFieldType.ELEMENT) { if(showPretty) { sb.append("\n"); sb.append(getLevelIndent()); } sb.append(toStartTag(name)); sb.append(toXmlValue()); sb.append(toEndTag(name)); } else { sb.append(" ").append(name).append("=\""); sb.append(toXmlValue()).append("\"");; } break; case StandardType.GROUP : // skip variable group if( getSize() == 0) { break; } if (isHidden) break; if(showPretty) { sb.append("\n"); sb.append(getLevelIndent()); } if(fieldType == 0) { sb.append(toStartTag(name)); } else { sb.append("<").append(name); } keyIter = childs.keySet().iterator(); while(keyIter.hasNext()) { String key = keyIter.next(); StandardItem item = childs.get(key); sb.append(item.toXML(encode, showPretty)); } if(fieldType == 0) { if(showPretty) { sb.append("\n"); sb.append(getLevelIndent()); } sb.append(toEndTag(name)); } else { sb.append(" />");; } break; case StandardType.GRID : if(showPretty) { sb.append(getLevelIndent()); } if (isHidden) break; for(int p=0; p group = list.get(p); keyIter = group.keySet().iterator(); while(keyIter.hasNext()) { String key = keyIter.next(); StandardItem item = group.get(key); sb.append(item.toXML(encode, showPretty)); } if(showPretty) { sb.append("\n"); sb.append(getLevelIndent()); } sb.append(toEndTag(name)); } break; case StandardType.FARRAY : if(showPretty) { sb.append(getLevelIndent()); } for(int p=0; p keyIter = null; try { switch(getType()) { case StandardType.MESSAGE : keyIter = childs.keySet().iterator(); while(keyIter.hasNext()) { String key = keyIter.next(); StandardItem item = childs.get(key); totalSize +=item.getBytesDataLength(charset); } break; case StandardType.FIELD : totalSize += getLength(); break; case StandardType.GROUP : // skip variable group if( getSize() == 0 //카카오뱅크 => 카카오카드 400응답시 아래 로직을 추가해야 전체건수에서 메시지부가 처리됨 //메시지부 size 0 refPath refValue 사용 해서 있고 없고 처리 && (StringUtils.isBlank(getRefPath()) || StringUtils.isBlank(getRefValue())) ) { break; } if (isHidden) break; keyIter = childs.keySet().iterator(); while(keyIter.hasNext()) { String key = keyIter.next(); StandardItem item = childs.get(key); totalSize +=item.getBytesDataLength(charset); } break; case StandardType.GRID : if( getSize() == 0 //반복그리드 관련해서 추가되야됩 && StringUtils.isBlank(getRefPath()) && StringUtils.isBlank(getRefValue()) ) { break; } if (isHidden) break; for(int p=0; p group = list.get(p); keyIter = group.keySet().iterator(); while(keyIter.hasNext()) { String key = keyIter.next(); StandardItem item = group.get(key); totalSize +=item.getBytesDataLength(charset); } } break; case StandardType.FARRAY : for(int p=0; p keyIter = null; // logger.debug("Encoding : {}", charset); try { switch(getType()) { case StandardType.MESSAGE : keyIter = childs.keySet().iterator(); while(keyIter.hasNext()) { String key = keyIter.next(); StandardItem item = childs.get(key); bos.write(item.toByteArray(withBizData,charset)); //하위로 내려갈때 withBizDat 값이 없어져서 추가 jun's 20231101 } break; case StandardType.FIELD : if (getValue() == null) { //데이타 타입에 따라서 패딩 변경 if (dataType == StandardDataType.STRING || dataType == StandardDataType.ZZ_STRING) { bos.write( ByteUtil.padding("", getLength(), (byte)' ')); } else if (dataType == StandardDataType.NUMBER || dataType == StandardDataType.LL_NUMBER) { bos.write( ByteUtil.padding("", getLength(), (byte)'0')); }else { bos.write( ByteUtil.padding(new byte[0], getLength()) ); } } else if (dataType == StandardDataType.STRING || dataType == StandardDataType.ZZ_STRING) { bos.write( ByteUtil.padding(getBytesValue(charset), getLength()) ); } else if (dataType == StandardDataType.NUMBER || dataType == StandardDataType.LL_NUMBER) { bos.write( ByteUtil.padding(getBytesValue(charset), getLength(), (byte)'0', true) ); } else { bos.write( ByteUtil.padding(getBytesValue(charset), getLength()) ); } break; case StandardType.GROUP : // skip variable group if( getSize() == 0 //카카오뱅크 => 카카오카드 400응답시 아래 로직을 추가해야 전체건수에서 메시지부가 처리됨 //메시지부 size 0 refPath refValue 사용 해서 있고 없고 처리 && (StringUtils.isBlank(getRefPath()) || StringUtils.isBlank(getRefValue())) ) { break; } if (isHidden) break; keyIter = childs.keySet().iterator(); while(keyIter.hasNext()) { String key = keyIter.next(); StandardItem item = childs.get(key); bos.write(item.toByteArray(withBizData,charset)); //하위로 내려갈때 withBizDat 값이 없어져서 추가 jun's 20231101 } break; case StandardType.GRID : if( getSize() == 0 //반복그리드 관련해서 추가되야됩 && StringUtils.isBlank(getRefPath()) && StringUtils.isBlank(getRefValue()) ) { break; } if (isHidden) break; for(int p=0; p group = list.get(p); keyIter = group.keySet().iterator(); while(keyIter.hasNext()) { String key = keyIter.next(); StandardItem item = group.get(key); bos.write(item.toByteArray(withBizData, charset)); //하위로 내려갈때 withBizDat 값이 없어져서 추가 jun's 20231101 } } break; case StandardType.FARRAY : for(int p=0; p> getList() { return list; } public void setList(ArrayList> list) { this.list = list; } public ArrayList getValues() { return values; } public void setValues(ArrayList values) { this.values = values; } private LinkedHashMap cloneMap(LinkedHashMap childs) { if(childs == null) return childs; LinkedHashMap newMap = new LinkedHashMap(); for(String key:childs.keySet()) try { newMap.put(key, (StandardItem)childs.get(key).clone()); } catch (CloneNotSupportedException e) { ; } return newMap; } @Override public Object clone() throws CloneNotSupportedException { StandardItem cloned = (StandardItem)super.clone(); if(childs != null) { cloned.childs = cloneMap(childs); } if(list != null) { ArrayList> clist = new ArrayList<>(); for(int idx=0; idx)values.clone()); } if(value != null) { cloned.setValue(String.copyValueOf(value.toCharArray())); } if(bytesValue != null) { byte[] clonedBytes = new byte[bytesValue.length]; System.arraycopy(bytesValue, 0, clonedBytes, 0, bytesValue.length); cloned.setBytesValue(clonedBytes); } return cloned; } }