JAX-WSを使ってSOAPヘッダに独自のヘッダを付け足す方法(続編)

以前に「JAX-WSを使ってSOAPヘッダに独自のヘッダを付け足す方法 - Tomute’s Notes」という記事に書いたのだが、JAX-WSを使ってWebサービス・クライアントを作成する際に、送信するSOAPリクエストに対して独自ヘッダを付け足したい場合には以下のようにする(下記の例はstringValueというようなヘッダを付け足す場合)。

import com.sun.xml.ws.developer.WSBindingProvider;
import com.sun.xml.ws.api.message.Headers;

HelloPort port = helloService.getHelloPort();
WSBindingProvider bp = (WSBindingProvider)port;

bp.setOutboundHeader(
    Headers.create(new QName("simpleHeader"),"stringValue")
);


しかし、上記の方法はJAX-WS 2.1.3以降でサポートされたものであり、現時点で最新のJDK 1.6(Update 12)に含まれているJAX-WS 2.1.1では利用する事が出来ない。
したがってJAX-WS 2.1.3より以前のバージョンを使って、SOAPヘッダに独自のヘッダを付け足す場合には、SOAPメッセージハンドラを利用した、より複雑な方法を取る必要がある。

具体的には以下のような実装となる。

import javax.xml.ws.Binding;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.handler.Handler;

HelloPort port = helloService.getHelloPort();
// メッセージハンドラの登録処理
Binding binding = ((BindingProvider)port).getBinding();
List<Handler> handlerList = binding.getHandlerChain();
handlerList.add(new ClientHandler());
binding.setHandlerChain(handlerList);

作成するメッセージハンドラのサンプルは以下。

import javax.xml.soap.*;
import javax.xml.ws.handler.*;
import javax.xml.ws.handler.soap.*;

public class ClientHandler implements SOAPHandler<SOAPMessageContext> {
    public Set<QName> getHeaders() { return Collections.EMPTY_SET; }

    public boolean handleMessage(SOAPMessageContext context) {
        try {
            Boolean outboundProperty =
              (Boolean)context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
            if (outboundProperty.booleanValue()) {
                // Outbound
                SOAPMessage msg = context.getMessage();
                SOAPPart part = msg.getSOAPPart();
                SOAPEnvelope envelope = part.getEnvelope();
                SOAPHeader header = envelope.addHeader();
                QName xmlName = new QName("simpleHeader");
                SOAPHeaderElement headerElement =
                    (SOAPHeaderElement)header.addChildElement(xmlName);
                headerElement.addTextNode("stringValue");
            } else {
                // Inbound
            }
        } catch (SOAPException ex) {
            return false;
        }
        return true;
    }
    
    public boolean handleFault(SOAPMessageContext context) { return true; }

    public void close(MessageContext context) {}
}


ちなみにJAX-RPCを使う場合には、更に少し実装が異なり、以下のような形になる。

import javax.xml.rpc.Stub

HelloPort port = helloService.getHelloPort();
HelloPort_Stub stub = (HelloPort_Stub)port;

// メッセージハンドラの登録処理
stub._getHandlerChain().add(new ClientHandler());

作成するメッセージハンドラのサンプルは以下。

import javax.xml.rpc.handler.*;
import javax.xml.rpc.handler.soap.*;
import javax.xml.soap.*;

public class ClientHandler implements Handler {
    public void destroy() {}

    public QName[] getHeaders() { return null; }

    public void init(HandlerInfo arg0) {}

    public boolean handleFault(MessageContext arg0) { return false; }

    public boolean handleRequest(MessageContext arg0) {
        try {
            SOAPMessageContext mc = (SOAPMessageContext) arg0;
            SOAPMessage msg = mc.getMessage();
            SOAPPart part = msg.getSOAPPart();
            SOAPEnvelope envelope = part.getEnvelope();
            SOAPHeader header = envelope.addHeader();
            QName xmlName = new QName("simpleHeader");
            SOAPHeaderElement headerElement =
                (SOAPHeaderElement)header.addChildElement(xmlName);
            headerElement.addTextNode("stringValue");
        } catch (SOAPException ex) {
            ex.printStackTrace();
            return false;
        }
        return true;
    }

    public boolean handleResponse(MessageContext arg0) { return false; }
}

参考: