最近一直在好奇一个问题,为什么PE框架在发报文的时候报文名字有个前缀fseg呢?为了解决心中的疑惑,去项目上找找代码一探究竟。
首先发送报文一定要引用transport,先看看transport里有什么东东。
<!-- 对接esb -->
<transport id="ESBXMLTransformerTransport" class="com.csii.cop.transport.XmlTransport">
//报文解析
<ref name="transformerFactory">ESBTransformerFactory</ref>
//socket通讯
<ref name="transport">ESBSimpleXMLTcpTransport</ref>
//响应报文特殊处理
<ref name="streamParser">StreamParser</ref>
//报文格式
<param name="formatName">XMLOutboundPacketESB</param>
//响应报文解析器
<param name="parseName">esbxmlPacketParser</param>
<param name="debug">true</param>
//打印日志路径
<param name="dumpPath">/home/weblogic/tmp</param>
//报文是否打印在日志里
<param name="singleLogFile">true</param>
</transport>
如果要发送报文,一定要调用transport.submit()方法,找到对应的transport实现类看下
@Override
public Object submit(Object obj) throws CommunicationException {
if (this.throttlePolicy != null) {
Object id = this.throttlePolicy.acquire(obj, 0);
if (id != null) {
try {
return submitInner(obj);
} finally {
this.throttlePolicy.free(id);
}
}
throw new ThrottleRejectException("");
}
return submitInner(obj);
}
可以看到具体的逻辑是在submitInner()方法中,进去看下
private Object submitInner(Object input) throws CommunicationException {
setInputData((Map) input);
try {
//获取报文树解析器(XMLOutboundPacketESB)
Transformer formater = this.transformerFactory.getTransformer(this.formatName);
if (this.headFormatter != null) {
input = this.headFormatter.format(input, (Map) input);
}
//组装发送报文数据
Object preData = formater.format(input, (Map) input);
//省略部分代码
} catch (TransformException e) {
throw new CommunicationException(e.getMessageKey(), e);
} finally {
unsetInputData();
}
}
此段代码可以看到formater.format()方法是关键,那么是如何实现的呢,transformerFactory.getTransformer()这个方法提示了我们寻找的方向。
找到transformerFactory声明位置
<!-- 对接ESB -->
<bean name="ESBTransformerFactory" class="com.csii.pe.transform.XmlTransformerFactory">
<param name="path">/META-INF/config/outbound/csxml/packets</param>
<param name="debug">false</param>
<param name="cacheEnable">false</param>
<map name="parsers">
<ref name="esbxmlPacketParser">esbXmlPacketParser</ref>
</map>
</bean>
/META-INF/config/outbound/csxml/packets 为报文存放路径
查看实现类XmlTransformerFactory
public class XmlTransformerFactory extends TransformerFactory {
public void setParsers(Map parsers) {
Iterator it = parsers.entrySet().iterator();
while (it.hasNext()) {
Entry entry = (Entry) it.next();
//获取key和value
super.addTransformer((String) entry.getKey(), (Transformer) entry.getValue());
}
}
}
查看实现类XmlTransformerFactory父类TransformerFactory的addTransformer方法实现逻辑
public Element getElement(String id) {
Element element;
if (this.cacheEnable) {
element = (Element) this.cache.get(id);
if (element != null) {
return element;
}
}
element = (Element) this.elements.get(id);
if (element == null) {
//找交易报文配置
element = (Element) this.getObject(this.pathPrefix + id + ".xml");
}
if (element == null) {
throw new PeRuntimeException("can\'t find :" + this.pathPrefix + id + ".xml");
} else {
if (element != null && element instanceof ElementFactoryAware) {
((ElementFactoryAware) element).setElementFactory(this);
}
this.cache.put(id, element);
return element;
}
}
到目前位置,找到的是公共报文配置XMLOutboundPacketESB.xml。
<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE segment SYSTEM "packet.dtd">
<Group name="Transaction" xmlHead="<?xml version="1.0" encoding="gbk"?>">
<Group name="Header">
<Group name="sysHeader">
<xmlTag tagName="msgId"> <String name="msgId" ></String></xmlTag>
<xmlTag tagName="msgDate" ><String name="msgDate"></String></xmlTag>
<xmlTag tagName="msgTime" ><String name="msgTime"></String></xmlTag>
<xmlTag tagName="serviceCd" ><String name="serviceCd"></String></xmlTag>
<xmlTag tagName="operation" ><String name="operation"></String></xmlTag>
<xmlTag tagName="clientCd" ><String name="clientCd" defaultValue="277"></String></xmlTag>
<xmlTag tagName="serverCd" ><String name="serverCd" ></String></xmlTag>
<xmlTag tagName="bizId" ><String name="bizId" ></String></xmlTag>
<xmlTag tagName="bizType" ><String name="bizType" ></String></xmlTag>
<xmlTag tagName="orgCode" ><String name="orgCode" defaultValue="01001"></String></xmlTag>
<xmlTag tagName="resCode" ><String name="resCode" ></String></xmlTag>
<xmlTag tagName="resText" ><String name="resText" ></String></xmlTag>
<xmlTag tagName="bizResCode" ><String name="bizResCode" ></String></xmlTag>
<xmlTag tagName="bizResText" ><String name="bizResText" ></String></xmlTag>
<xmlTag tagName="authId" ><String name="authId" ></String></xmlTag>
<xmlTag tagName="authPara" ><String name="authPara" ></String></xmlTag>
<xmlTag tagName="authContext" ><String name="authContext" ></String></xmlTag>
<xmlTag tagName="pinIndex" ><String name="pinIndex" ></String></xmlTag>
<xmlTag tagName="pinValue" ><String name="pinValue" ></String></xmlTag>
<xmlTag tagName="ver" ><String name="ver" ></String></xmlTag>
</Group>
</Group>
<Group name="Body">
<Group name="request">
<Group name="bizHeader">
<include keyName="biz"></include>
</Group>
<Group name="bizBody">
<include keyName="_HostTransactionCode"></include>
</Group>
</Group>
</Group>
</Group>
注意,<include keyName="_HostTransactionCode"></include>这句话写出了我们交易将要使用的报文名称
回头看下formater.format()具体实现类XmlSegment.calss
public class XmlSegment extends Segment {
private byte[] xmlHeadBytes;
private String tagName;
private byte[] endXml;
private String includePrefix = "fseg";//不远万里,终于找到你
private byte[] beginXml;
private Map attributes;
private Expr expr;
private boolean option = true;
private String xmlHead;
private boolean format = false;
private boolean skipBody = false;
private static final String NEWLINE = "\r\n";
private static final byte[] NEWLINEBYTES = "\r\n".getBytes();
private static Pattern pattern = Pattern.compile("([^={}]{1,})=\\{([^{}]{1,})\\}");
public Object format(Object data, Map context) throws TransformException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
this.format(out, data, context);
return out.toByteArray();
}
public void format(OutputStream out, Object data, Map context) throws TransformException {
try {
if (!this.skipBody) {
for (int i = 0; i < this.elements.size(); ++i) {
Element ele = (Element) this.elements.get(i);
if (ele instanceof Format2Stream) {
if (ele instanceof Segment) {
Object obj = ((Map) data).get(ele.getName());
if (obj == null) {
((Format2Stream) ele).format(out, data, (Map) data);
} else {
((Format2Stream) ele).format(out, obj, (Map) data);
}
} else {
((Format2Stream) ele).format(out, ((Map) data).get(ele.getName()), (Map) data);
}
} else if (ele instanceof TransformerElement) {
} else if (ele instanceof Include) {
Include include = (Include) ele;
String condition = include.getCondition();
if (condition != null) {
OgnlExpr includeT = new OgnlExpr();
boolean includedData = ((Boolean) includeT.getValue(condition, (Map) data, (Map) data)).booleanValue();
if (!includedData) {
continue;
}
}
//fseg最终在这里使用includePrefix = fseg
Transformer transformer = (Transformer) include.getElement(this.includePrefix, (Map) data);
}
}
}
out.write(this.endXml);
if (this.format) {
out.write(NEWLINEBYTES);
}
}
} catch (Exception arg10) {
throw new TransformException(this.getClass().getName() + ".format error: " + this.getName(), arg10);
}
}
}
原来是XmlSegment.calss加了fseg,不远万里,终于找到你
by CSII@王大仙