web-dev-qa-db-ja.com

AXIS2によって作成されたADBスタブを使用してクライアント側で生のXMLSOAP応答を取得する

AXIS2によって作成されたADBスタブを使用してSOAPサービスにアクセスします。サービスによって返されるAxisFaultの生のXML応答をログに記録したいと思います。これらのエラーを「」としてキャッチできます。 ServiceError」。ただし、生のXMLを取得する方法が見つかりません(以下の例を参照)。

GetOMElementを使用して、通常の処理のために生のXML要求/応答にアクセスする方法を見つけました(以下の例を参照)。ただし、これは障害に対しては機能しません。

ADBスタブを使用して生のXML障害を取得するにはどうすればよいですか?

例Javaコード:

    public void testRequest(String URL) throws AxisFault {
        MyServiceStub myservice = new MyServiceStub(URL);
        MyRequest req = new MyRequest();
        try {
            TypeMyFunctionResponse response = myservice.myFunction(req);

            // logging full soap response
            System.out.println("SOAP Response: "
                    + response.getOMElement(null,
                            OMAbstractFactory.getOMFactory())
                            .toStringWithConsume());
        } catch (RemoteException e) {
            //...
        } catch (ServiceError e) {
            // how to get the raw xml?
        }
    }

フェッチしてログに記録したい障害応答の例:

<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
    <soapenv:Body>
        <soapenv:Fault>
            <soapenv:Code>
                <soapenv:Value>soapenv:Receiver</soapenv:Value>
            </soapenv:Code>
            <soapenv:Reason>
                <soapenv:Text xml:lang="en-US">service error</soapenv:Text>
            </soapenv:Reason>
            <soapenv:Detail>
                <ns1:error xmlns:ns1="http://www.somehost.com/webservices/someservice">
                    <ns1:code>500</ns1:code>
                    <ns1:messageText>some fault message</ns1:messageText>
                </ns1:error>
            </soapenv:Detail>
        </soapenv:Fault>
    </soapenv:Body>
</soapenv:Envelope>
9
Daniel

Joerglが提案したように、「SOAPHandler」を使用してADBスタブをJAX-WS-onesに変更し、次の説明に従ってリクエスト、応答、および障害をログに記録しました。 http://www.mkyong.com/webservices/jax -ws/jax-ws-soap-handler-in-client-side /

私のハンドラーは、log4jを使用して適切にフォーマットされたXMLをログに記録するために次のようになります。

public class RequestResponseHandler  implements SOAPHandler<SOAPMessageContext> {

    private static Logger log = Logger.getLogger(RequestResponseHandler.class);
    private Transformer transformer = null;
    private DocumentBuilderFactory docBuilderFactory = null;
    private DocumentBuilder docBuilder = null;

    public RequestResponseHandler() {
        try {
            transformer = TransformerFactory.newInstance().newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty("{http://xml.Apache.org/xslt}indent-amount", "5");
            docBuilderFactory = DocumentBuilderFactory.newInstance();
            docBuilder = docBuilderFactory.newDocumentBuilder();
        } catch (TransformerConfigurationException
                | TransformerFactoryConfigurationError
                | ParserConfigurationException e) {
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public void close(MessageContext arg0) {
    }

    @Override
    public boolean handleFault(SOAPMessageContext messageContext) {
        log(messageContext);
        return true;
    }

    @Override
    public boolean handleMessage(SOAPMessageContext messageContext) {
        log(messageContext);
        return true;
    }

    private void log(SOAPMessageContext messageContext) {
        String xml = "";
        SOAPMessage msg = messageContext.getMessage();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            msg.writeTo(out);
            xml = out.toString("UTF-8");
        } catch (Exception e) {
            log.error(e.getMessage(),e);
        }       

        String direction = "";
        Boolean outbound = (Boolean) messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); 
        if (outbound) { 
            direction += "Request: \n"; 
        } else { 
            direction += "Response: \n";
        } 

        log.info(direction + getXMLprettyPrinted(xml));     
    }

    @Override
    public Set<QName> getHeaders() {
        return Collections.emptySet();
    }


    public String getXMLprettyPrinted(String xml) {

        if (transformer == null || docBuilder == null)
            return xml;

        InputSource ipXML = new InputSource(new StringReader(xml));
        Document doc;

        try {
            doc = docBuilder.parse(ipXML);
            StringWriter stringWriter = new StringWriter();
            StreamResult streamResult = new StreamResult(stringWriter);
            DOMSource domSource = new DOMSource(doc);
            transformer.transform(domSource, streamResult);
            return stringWriter.toString();
        } catch (SAXException | IOException | TransformerException e) {
            log.error(e.getMessage(), e);
            return xml;
        }
    }
}

さらに、アプリケーションコードで生のXMLを再利用したかったのです。そのため、このデータをSOAPHandlerからクライアントコードに転送する必要がありました。これを行う方法はあまり明白ではありませんでした。この問題の詳細については、この記事を参照してください。 soapMessageと一緒にsoapハンドラーに追加のフィールドを送信する方法

2
Daniel

以下はおそらくあなたが探しているものです。yourStubはwsdl2Javaを介して生成したものであり、リクエストを行った後に以下の行を使用します。メッセージはlastOperationに設定され、実際に電話をかけるときに送信されます。

request = yourStub._getServiceClient().getLastOperationContext().getMessageContext("Out")
              .getEnvelope().toString());

response = yourStub._getServiceClient().getLastOperationContext().getMessageContext("In")
              .getEnvelope().toString());

お役に立てば幸いです。

7
Ducane

この質問はすでによく答えられていますが、私はこれを早く行う必要があり、自分の制約に合う適切な答えを見つけるのに苦労したので、後世のために自分自身を追加しています。

JDK 1.4を実行している最近のプロジェクトでは、Axis 2バージョン1.4.1でこれを行う必要がありましたが、これを読んだところ、JAX-WSスタブではサポートされていませんでした。 SoapBuilderを独自のビルダークラスでラップし、入力ストリームをコピーして、そのコピーをSoapBuilderに渡すことにより、入力をキャプチャする間、ADBスタブを保持することになりました。

public class SOAPBuilderWrapper implements Builder {
    private String lastResponse;

    private SOAPBuilder builder = new SOAPBuilder();

    private static final int BUFFER_SIZE = 8192;

    public OMElement processDocument(InputStream inputStream,
            String contentType, MessageContext messageContext) throws AxisFault {
        ByteArrayOutputStream copiedStream = new ByteArrayOutputStream();
        try {
            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead = inputStream.read(buffer);
            while (bytesRead > -1) {
                copiedStream.write(buffer, 0, bytesRead);
                bytesRead = inputStream.read(buffer);
            }
            lastResponse = copiedStream.toString();

        } catch (IOException e) {
            throw new AxisFault("Can't read from input stream", e);
        }
        return builder.processDocument(
                new ByteArrayInputStream(copiedStream.toByteArray()),
                contentType, messageContext);
    }

    public String getLastResponse() {
        return lastResponse;
    }
}

さまざまな理由で、axis2.xmlを使用した構成には問題があったため、ラッパーは次のようにプログラムで追加されました。

SoapBuilderWrapper responseCaptor = new SoapBuilderWrapper();
AxisConfiguration axisConfig = stub._getServiceClient().getAxisConfiguration();
axisConfig.addMessageBuilder("application/soap+xml", responseCaptor);
axisConfig.addMessageBuilder("text/xml", responseCaptor);

これにより、サービスが呼び出された後、responseCaptor.getLastResponse()を使用して応答を取得できます。

5
Taufiq

Ducaneの返信に関連して:

response = yourStub._getServiceClient().getLastOperationContext().getMessageContext("In")
          .getEnvelope().toString());

com.ctc.wstx.exc.WstxIOException例外とメッセージ:クローズドストリームでの読み取りを試みましたで失敗します。

3
dayer

Axis2の場合、実装を変更する余裕がない/またはxyzの理由でJAS-WSを使用したくない人は

@Ducaneが便利だとわかった

request = >yourStub._getServiceClient().getLastOperationContext().getMessageContext("Out")
         .getEnvelope().toString());

response = >yourStub._getServiceClient().getLastOperationContext().getMessageContext("In")
         .getEnvelope().toString());

@dayerの回答で示唆されているように

response = >yourStub._getServiceClient().getLastOperationContext().getMessageContext("In")
     .getEnvelope().toString());

com.ctc.wstx.exc.WstxIOException例外とメッセージで失敗します:>閉じたストリームで読み取りを試みました。

「In」メッセージラベルの問題がわからない、

しかし、検索中に、次のJIRAチケットが見つかりました https://issues.Apache.org/jira/browse/AXIS2-5469 これは https://issues.Apache.org/jira/browser/AXIS2-5202 そして、議論の中で、次のコードを使用してこの問題を解決するWAの1つを見つけました。私は、soapRequestの応答メッセージを聞くことができます。

stub._getServiceClient().getAxisService().addMessageContextListener(
new MessageContextListener() {
    public void attachServiceContextEvent(ServiceContext sc,
        MessageContext mc) {}
    public void attachEnvelopeEvent(MessageContext mc) {
        try
        { mc.getEnvelope().cloneOMElement().serialize(System.out); }
        catch (XMLStreamException e) {}
    }
});

ここでMessageContextListnerは引数定義の匿名内部クラスであるため、それはすべての囲んでいる変数にアクセスできます。したがって、文字列クラス変数をlatestSoapResponseとして定義し、さらに使用するために応答を格納しました。

ByteArrayOutputStream baos = new ByteArrayOutputStream();
mc.getEnvelope().cloneOMElement().serialize(baos); 
latestSoapResponse=baos.toString();

SOAPリクエストを生成する前にリスナーを追加する必要があることに注意してください。 Request MessageContextは、SOAPリクエストを生成した後でのみ使用できます。

また、デバッグ目的で生のsoapリクエスト応答が必要な場合は、@ Sankerからの回答を参照してください。 ここ で、JVM引数を使用してApacheコモンログを有効にします。

1
Kavan