6

JAX-WS-RI または Metro を使用すると、com.sun.xml.ws.api.server.AsyncProvider インターフェイスを使用して WebService を作成できます。

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> {
...

次に、メッセージを解析してそれに応じて処理するものを書くことができます

public void invoke(Source source, AsyncProviderCallback<Source> cbak, WebServiceContext ctxt) {
        DOMResult dom = new DOMResult();
        Transformer trans = TransformerFactory.newInstance().newTransformer();
        trans.transform(source, dom);

        XPath xpath = XPathFactory.newInstance().newXPath();
        xpath.setNamespaceContext(new MyNamespaceContext());

        String opName = (String) xpath.evaluate("name(/S:Envelope/S:Body/X:*[1])", dom.getNode(), XPathConstants.STRING);

        if(knownOp(opName)) {
            doOp(opName, dom.getNode(), cbak);
        }
        else {
            doFault("Unknown operation " + opName, cbak);
        }

}

ただし、これを行う理由の一部は、既存の XML ベースのアプリケーションを SOAP スタックに適合させるためです。アプリケーションは、受け取るメッセージの完全なスキーマ セットを定義し、サービスを定義するための WSDL を簡単に生成できます。

小さな XML メッセージの場合、これはすべて正常に機能します。

ただし、メッセージがかさばる一部の操作で、よりストリーム指向の方法で XML を処理したい場合、MTOM 添付ファイルを使用すると 2 つの問題に遭遇します。プロバイダーの設定を次のように変更します。

import com.sun.xml.ws.api.message.Message;
import javax.xml.ws.soap.MTOM;
import com.sun.xml.ws.developer.StreamingAttachment;
import com.sun.xml.ws.developer.StreamingDataHandler;

ServiceMode(value=Service.Mode.MESSAGE)
@WebServiceProvider()
@StreamingAttachment(parseEagerly=true, memoryThreshold=1000L)
@MTOM(enabled=true, threshold=1000) 
public class AddNumbersAsynchImplMessage implements AsyncProvider<Message> {
...

適切な MTOM ポリシーを WSDL に追加します。

<definitions
        name="AddNumbersAsynch"
        targetNamespace="http://asynch.duke.example.org"
        xmlns:tns="http://asynch.duke.example.org"
        xmlns="http://schemas.xmlsoap.org/wsdl/"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
        xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
        xmlns:wsrm="http://docs.oasis-open.org/ws-rx/wsrmp/200702"
        xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
        xmlns:wsoma="http://schemas.xmlsoap.org/ws/2004/09/policy/optimizedmimeserialization"
        xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
        <wsp:Policy wsu:Id="AddNumbersAsynch_policy">
            <wsam:Addressing wsp:Optional="false" />
            <wsoma:OptimizedMimeSerialization/>
        </wsp:Policy>

そして、この操作のメッセージ スキーマを適切に宣言します。

        <complexType name="sendBulk">
            <sequence>
                <element name="data" type="base64Binary"
                    xmime:expectedContentTypes="application/xml"
                    xmlns:xmime="http://www.w3.org/2005/05/xmlmime"/>
            </sequence>
        </complexType>
        <element name="sendBulk" type="tns:sendBulk"/>

        <complexType name="sendBulkResponse">
            <sequence>
                <element name="return" type="xsd:string" />
            </sequence>
        </complexType>
        <element name="sendBulkResponse" type="tns:sendBulkResponse"/>

必要に応じてバインディングを設定します。

<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 ダンプは、データが「メッセージ本文」に適切な xop:include 要素を持つマルチパート MIME として送信されていることを示しています。

---[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);

うまくいけば、添付ファイル パーサーは受信側の HTTP ストリームのその部分をまだすべて読み取っていないか、ファイルに分割されている場合は、チャンクごとに読み取ることができます。問題は、受信メッセージを添付ファイルの base64 でエンコードされたデータに変換しないメッセージを解析する方法が見つからないことです。要素の開始を示す SAX/StaX イベントを取得した後、base64 でエンコードされたデータである文字イベントが続きます。StreamMessage のコードを見ると、メッセージが既にバインドされている既存の XMLStreamReader の「前」に、XMLReader や XMLStreamReader などを「挿入」する方法はありません (メッセージ処理の途中なので驚くことではありません)。しかし、その XMLStreamReader 実装は com.sun.xml.ws.encoding.MtomCodec$MtomXMLStreamReaderEx で、常に ' の添付ファイルをインラインでメモリにアンパックします。com.sun.xml.ws.encoding.MtomCodec クラスをパラメータ化して、添付ファイルをインラインでアンパックする内部 MtomXMLStreamReaderEx クラスに最初にイベントを渡さないようにする方法はありません。

添付ファイルを一時ファイルに読み取ってから、メッセージ コンテキストの添付ファイルを FileDataSource に置き換えようとしましたが、Metro はこれらを無視するため、元の DataSource に 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);
            }

アノテーションを無効に設定して、プロバイダーで MTOM をオフにしてみました。

@MTOM(enabled=false) 

それを削除してから StreamingAttachment アノテーションを削除しても無駄です。また、sun-jaxws.xml ファイルの endpoint 要素に enable-mtom="false" 属性を設定しましたが、やはり無駄でした。xop:Include の解析が組み込まれているようです。可能であればクライアントに MTOM を使用してもらいたいので、wsdl を変更したくありません。(ただし、以下のswaRefの回答を参照してください)

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"/>

また、新しいクライアントを生成し、sendBulk メソッドを別の方法で呼び出す必要があります。

FileDataSource newSource = new FileDataSource(file);
DataHandler data = new DataHandler(newSource);
String result = port.sendBulk(data);

しかし、データ要素を解析すると、対応するcidが取得され、それを使用して必要に応じて添付ファイルを取得できます。

DataHandler handler = attachments.get(dataText.substring("cid:".length()));
InputStream input = handler.getInputStream();

したがって、MTOM と Metro を使用すると、データ要素を解析する時点まで添付ファイルが読み取られていないか、実際にチャンクで効率的に一時ファイルにストリーミングされていない可能性がありますが、入力メッセージの「残り」を読み取る方法がありません。愛着の全体をメモリに読み込まずに、自滅しているように見えますか? Metro のダンプとは別に - 提案 re: Axis、CXF を歓迎します - 誰かが発見したこれを回避する方法はありますか?

機能リクエストを記録しました。

4

0 に答える 0