Java 如何在Metro下解析带有MTOM附件的入站邮件,而不提取所有附件数据?

Java 如何在Metro下解析带有MTOM附件的入站邮件,而不提取所有附件数据?,java,jax-ws,mtom,xop,Java,Jax Ws,Mtom,Xop,使用JAX-WS-RI或Metro,我可以使用com.sun.xml.WS.api.server.AsyncProvider接口编写Web服务 我可以选择获取整个消息,包括SOAP头 import javax.xml.transform.Source; import com.sun.xml.ws.api.server.AsyncProvider; import com.sun.xml.ws.api.server.AsyncProviderCallback; import javax.xml.w

使用JAX-WS-RI或Metro,我可以使用com.sun.xml.WS.api.server.AsyncProvider接口编写Web服务

我可以选择获取整个消息,包括SOAP头

import javax.xml.transform.Source;
import com.sun.xml.ws.api.server.AsyncProvider;
import com.sun.xml.ws.api.server.AsyncProviderCallback;

import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.WebServiceProvider;


@ServiceMode(value=Service.Mode.MESSAGE)
@WebServiceProvider()
public class AddNumbersAsynchImpl implements AsyncProvider<Source> {
...
http转储显示数据以多部分mime的形式发送,并在“消息体”中包含相应的xop:include元素

---[HTTP request - http://localhost:8080/ProviderTest2/addnumbersAsynchMessage]---
Accept: text/xml, multipart/related
Content-Type: multipart/related;start="<rootpart*daff762b-9651-40aa-ae2f-30d30a3c5e2e@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:daff762b-9651-40aa-ae2f-30d30a3c5e2e";start-info="text/xml"
SOAPAction: "http://message.asynch.duke.example.org/AddNumbersPortType/sendBulkRequest"
User-Agent: Metro/2.2 (branches/2.2-7015; 2012-02-20T20:31:25+0000) JAXWS-RI/2.2.6 JAXWS/2.2 svn-revision#unknown
--uuid:daff762b-9651-40aa-ae2f-30d30a3c5e2e
Content-Id: <rootpart*daff762b-9651-40aa-ae2f-30d30a3c5e2e@example.jaxws.sun.com>
Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
Content-Transfer-Encoding: binary

<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Header><To xmlns="http://www.w3.org/2005/08/addressing">http://localhost:8080/ProviderTest2/addnumbersAsynchMessage</To><Action xmlns="http://www.w3.org/2005/08/addressing" xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" S:mustUnderstand="1">http://message.asynch.duke.example.org/AddNumbersPortType/sendBulkRequest</Action><ReplyTo xmlns="http://www.w3.org/2005/08/addressing">
    <Address>http://www.w3.org/2005/08/addressing/anonymous</Address>
</ReplyTo><FaultTo xmlns="http://www.w3.org/2005/08/addressing">
    <Address>http://www.w3.org/2005/08/addressing/anonymous</Address>
</FaultTo><MessageID xmlns="http://www.w3.org/2005/08/addressing">uuid:406ce4bc-7332-4849-b16b-69cec6ca21ea</MessageID></S:Header><S:Body><sendBulk xmlns="http://message.asynch.duke.example.org"><data><xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:5f88ee1b-0aa1-46ef-bad3-93df9b2aaa02@example.jaxws.sun.com"/></data></sendBulk></S:Body></S:Envelope>
--uuid:daff762b-9651-40aa-ae2f-30d30a3c5e2e
Content-Id: <5f88ee1b-0aa1-46ef-bad3-93df9b2aaa02@example.jaxws.sun.com>
Content-Type: application/xml; charset=UTF-8
Content-Transfer-Encoding: binary

....snip!
希望附件解析器还没有读取输入HTTP流的所有部分,或者如果已经读取了,它已经将其分块到一个文件中,然后我可以逐块读取它。 问题是我找不到一种解析消息的方法,这种方法不会将传入的数据转换为附件中的base64编码数据。 在我得到指示元素开始的SAX/StaX事件之后,它后面跟着一个characters事件,它是base64编码的数据。 查看StreamMessage的代码,无法“插入”消息已绑定到的现有XMLStreamReader之前的任何XMLReader或XMLStreamReader等(这并不奇怪,因为我们正在进行消息处理)。 但XMLStreamReader实现是一个com.sun.xml.ws.encoding.MtomCodec$MtomXMLStreamReaderEx,它总是将附件“解压”到内存中。 无法对com.sun.xml.ws.encoding.MtomCodec类进行参数化,以便它不会首先将事件传递给内部MtomXMLStreamReaderEx类,该类将内联解压缩附件

我试图将附件读入一个临时文件,然后用消息上下文附件替换FileDataSource,但由于Metro忽略了这些附件,这只会使原始数据源抛出ReadOnce类型错误

Map<String, DataHandler> attachments = (Map<String, DataHandler>) ctxt.getMessageContext().get(javax.xml.ws.handler.MessageContext.INBOUND_MESSAGE_ATTACHMENTS);
            HashMap<String, DataHandler> clonedAttachments = new HashMap<String, DataHandler>(attachments);
            for(String attachmentKey: attachments.keySet()) {
                StreamingDataHandler handler = (StreamingDataHandler) attachments.get(attachmentKey);
                File tempFile = File.createTempFile("Attachment" + attachmentKey, ".xmlb64", new File("C:\\Users\\Administrator\\workspaceTool1\\TomcatWorkingDir"));
                handler.moveTo(tempFile);
                FileDataSource newSource = new FileDataSource(tempFile);
                clonedAttachments.put(attachmentKey, new DataHandler(newSource));
                System.out.println("Got attachment " + attachmentKey + " of type " + attachments.get(attachmentKey));
            }
            if(attachments.isEmpty()) {
                System.out.println("Got No attachments");
            }
            else {
                ctxt.getMessageContext().put(javax.xml.ws.handler.MessageContext.INBOUND_MESSAGE_ATTACHMENTS, clonedAttachments);
            }
然后删除它,然后删除StreamingAttachment注释,但没有任何效果。我还在sun-jaxws.xml文件的endpoint元素中为它设置了enable mtom=“false”属性,同样没有用;似乎xop:Include解析是硬连线的。我不想更改wsdl,因为我确实希望客户端尽可能使用MTOM。(但请看下面我的回答)

如果我使用swaRef,我可以让Metro做我想做的事情,但我的理解是MTOM是获得支持的协议?使用swaRef,我必须编辑WSDL

<types>


        <xsd:schema
            xmlns="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://swaRef.asynch.duke.example.org"
            elementFormDefault="qualified">

        <xsd:import namespace="http://ws-i.org/profiles/basic/1.1/xsd"  
                        schemaLocation="http://www.ws-i.org/profiles/basic/1.1/swaref.xsd"/>



            <complexType name="sendBulk">
                <sequence>
                    <element name="data" type="wsi:swaRef"
                        xmlns:wsi="http://ws-i.org/profiles/basic/1.1/xsd"/>
                </sequence>
            </complexType>
            <element name="sendBulk" type="tns:sendBulk"/>
但是现在当我解析数据元素时,我得到了相应的cid,然后我可以根据自己的意愿使用它来检索附件

DataHandler handler = attachments.get(dataText.substring("cid:".length()));
InputStream input = handler.getInputStream();
因此,使用MTOM和Metro时,虽然附件可能尚未读取到我解析数据元素的程度,或者确实没有有效地将其分块传输到临时文件中,但如果不将整个附件读取到内存中,我就无法读取输入消息的“其余部分”,这似乎是自欺欺人的? 除了抛售Metro之外——关于Axis的建议,CXF表示欢迎——有人发现了解决这个问题的方法吗

记录

<binding name="AddNumbersBinding" type="tns:AddNumbersPortType">
<wsp:PolicyReference URI="#AddNumbersAsynch_policy"/>
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
    <operation name="sendBulk">
        <soap:operation soapAction="" />
        <input>
            <soap:body use="literal" />
        </input>
        <output>
            <soap:body use="literal" />
        </output>
    </operation>
</binding>
port = new AddNumbersService().getAddNumbersPort(new SyncStartForAsyncFeature(), new MTOMFeature(1000));
  Source data = new StreamSource(new FileInputStream(file));
  String result = port.sendBulk(data);
---[HTTP request - http://localhost:8080/ProviderTest2/addnumbersAsynchMessage]---
Accept: text/xml, multipart/related
Content-Type: multipart/related;start="<rootpart*daff762b-9651-40aa-ae2f-30d30a3c5e2e@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:daff762b-9651-40aa-ae2f-30d30a3c5e2e";start-info="text/xml"
SOAPAction: "http://message.asynch.duke.example.org/AddNumbersPortType/sendBulkRequest"
User-Agent: Metro/2.2 (branches/2.2-7015; 2012-02-20T20:31:25+0000) JAXWS-RI/2.2.6 JAXWS/2.2 svn-revision#unknown
--uuid:daff762b-9651-40aa-ae2f-30d30a3c5e2e
Content-Id: <rootpart*daff762b-9651-40aa-ae2f-30d30a3c5e2e@example.jaxws.sun.com>
Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
Content-Transfer-Encoding: binary

<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Header><To xmlns="http://www.w3.org/2005/08/addressing">http://localhost:8080/ProviderTest2/addnumbersAsynchMessage</To><Action xmlns="http://www.w3.org/2005/08/addressing" xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" S:mustUnderstand="1">http://message.asynch.duke.example.org/AddNumbersPortType/sendBulkRequest</Action><ReplyTo xmlns="http://www.w3.org/2005/08/addressing">
    <Address>http://www.w3.org/2005/08/addressing/anonymous</Address>
</ReplyTo><FaultTo xmlns="http://www.w3.org/2005/08/addressing">
    <Address>http://www.w3.org/2005/08/addressing/anonymous</Address>
</FaultTo><MessageID xmlns="http://www.w3.org/2005/08/addressing">uuid:406ce4bc-7332-4849-b16b-69cec6ca21ea</MessageID></S:Header><S:Body><sendBulk xmlns="http://message.asynch.duke.example.org"><data><xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:5f88ee1b-0aa1-46ef-bad3-93df9b2aaa02@example.jaxws.sun.com"/></data></sendBulk></S:Body></S:Envelope>
--uuid:daff762b-9651-40aa-ae2f-30d30a3c5e2e
Content-Id: <5f88ee1b-0aa1-46ef-bad3-93df9b2aaa02@example.jaxws.sun.com>
Content-Type: application/xml; charset=UTF-8
Content-Transfer-Encoding: binary

....snip!
public void invoke(Message source, AsyncProviderCallback<Message> cbak, WebServiceContext ctxt) {

        Map<String, DataHandler> attachments = (Map<String, DataHandler>) ctxt.getMessageContext().get(javax.xml.ws.handler.MessageContext.INBOUND_MESSAGE_ATTACHMENTS); 
        for(String attachmentKey: attachments.keySet()) {
            StreamingDataHandler handler = (StreamingDataHandler) attachments.get(attachmentKey);
            System.out.println("Got attachment " + attachmentKey + " of type " + attachments.get(attachmentKey));
        }
        if(attachments.isEmpty()) {
            System.out.println("Got No attachments");
        }
XMLStreamWriter sw = new MyXMLStreamWriter();
source.writeTo(sw);
Map<String, DataHandler> attachments = (Map<String, DataHandler>) ctxt.getMessageContext().get(javax.xml.ws.handler.MessageContext.INBOUND_MESSAGE_ATTACHMENTS);
            HashMap<String, DataHandler> clonedAttachments = new HashMap<String, DataHandler>(attachments);
            for(String attachmentKey: attachments.keySet()) {
                StreamingDataHandler handler = (StreamingDataHandler) attachments.get(attachmentKey);
                File tempFile = File.createTempFile("Attachment" + attachmentKey, ".xmlb64", new File("C:\\Users\\Administrator\\workspaceTool1\\TomcatWorkingDir"));
                handler.moveTo(tempFile);
                FileDataSource newSource = new FileDataSource(tempFile);
                clonedAttachments.put(attachmentKey, new DataHandler(newSource));
                System.out.println("Got attachment " + attachmentKey + " of type " + attachments.get(attachmentKey));
            }
            if(attachments.isEmpty()) {
                System.out.println("Got No attachments");
            }
            else {
                ctxt.getMessageContext().put(javax.xml.ws.handler.MessageContext.INBOUND_MESSAGE_ATTACHMENTS, clonedAttachments);
            }
@MTOM(enabled=false) 
<types>


        <xsd:schema
            xmlns="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://swaRef.asynch.duke.example.org"
            elementFormDefault="qualified">

        <xsd:import namespace="http://ws-i.org/profiles/basic/1.1/xsd"  
                        schemaLocation="http://www.ws-i.org/profiles/basic/1.1/swaref.xsd"/>



            <complexType name="sendBulk">
                <sequence>
                    <element name="data" type="wsi:swaRef"
                        xmlns:wsi="http://ws-i.org/profiles/basic/1.1/xsd"/>
                </sequence>
            </complexType>
            <element name="sendBulk" type="tns:sendBulk"/>
FileDataSource newSource = new FileDataSource(file);
DataHandler data = new DataHandler(newSource);
String result = port.sendBulk(data);
DataHandler handler = attachments.get(dataText.substring("cid:".length()));
InputStream input = handler.getInputStream();