SOAP MessagingにおけるSOAP Bodyの操作(AXIS 1.3)
SOAP Messagingのメッセージ送受信の方法が分かったので,今度は送受信するメッセージの解析や作成方法を調査してみた.
今回は,クライアント側から現在時刻のミリ秒と日付フォーマットをサーバに送信し,サーバ側ではそのミリ秒を指定されたフォーマットに変換してから返すというサンプルを作成した.
deploy.wsddは以下.
要求電文は以下.
これに対する回答電文は以下.
今回のポイントは以下である.
- クライアント側での要求電文の動的な作成
- サーバ側での要求電文の解析と,それに応じた回答電文の動的な作成
- サーバ側での動的な処理にともなうエラーハンドリング
- クライアント側での回答電文の解析
以下にサンプルのクライアントのコードを示す.
メソッドcreateReqSOAPBodyElementにおいて,要求電文のSOAPBodyを作成している.
private static SOAPBodyElement createReqSOAPBodyElement() throws SOAPException {
SOAPBodyElement resultElement = new SOAPBodyElement();
resultElement.setQName(new QName("", "requestMessage"));
SOAPElement parameterElement = resultElement.addChildElement("parameter");
SOAPElement valueElement = parameterElement.addChildElement("value");
valueElement.addTextNode(Long.toString(Calendar.getInstance().getTimeInMillis()));
SOAPElement formatElement = parameterElement.addChildElement("format");
formatElement.addTextNode("yyyy-MM-dd");
return resultElement;
}
要求電文はXML文書であることもあり,その作成は上記のようにDOMプログラミングの拡張のようになっている.
SOAPBodyを作成すれば,あとのSOAPEnvelopeはライブラリ側でやってくれるので,サービスの呼び出しはinvokeするだけでよい.
SOAPBodyElement[] input = new SOAPBodyElement[1];
input[0] = createReqSOAPBodyElement();
Object result = call.invoke(input);
以下にサンプルのサービスDateFormatServiceを示す.
メソッドcreateDateFormatParamsにおいて,要求電文の解析を行っている.
パラメータのinputは,呼び出し元メソッドformatDateでAXISからわたされるオブジェクトである.
サーバ側のログで
StringWriter writer = new StringWriter();
XMLUtils.ElementToWriter(rootElement, writer);
System.out.println("rootElement = " + writer.toString());
を確認したところ,
rootElement = <requestMessage><parameter><value>1129966273627</value><format>yyyy-MM-dd</format></parameter></requestMessage>となっていた. すなわちdeployment.wsddにて登録したメソッドformatDateの引数には,SOAPBodyがDocumentオブジェクトとして渡される. ここまで分かれば,あとは要求電文の作成と同様である. ただし,拡張ではなくDOMプログラミングそのものになっている点に注意. 回答電文の作成はメソッドcreateResDocumentにおいて行っている. こちらはDOMプログラミングそのままとなっている. このようにサーバ側処理は完全にDOMプログラミングとなっており,AXIS特有の要素クラスをほとんどインポートせずに実装できている点に注意.
SOAPでは,サーバ側で処理異常があった場合,SOAPFaultを返すことになっている.
さらにHTTPバインディングの場合は,HTTPリターンコードは500とすることになっている.
AXISを使用する場合,サービスメソッドがAxisFaultを投げれば,上記のような処理を行ってくれる.
今回のサービスは,SimpleDateFormatがサポートしていないものを日付フォーマットに指定すると,サーバ側で処理が継続できない.
したがって,以下の要求はフォーマットに"XX"などとあり不正である.
これに対する回答は以下である.
まず,HTTPリターンコードが500となっている.
さらにSOAPBodyにはsoapenv:Faultという要素ある.
サービス処理を行うメソッドからAxisFautlを投げると,Axisがこの要素以下を作成して回答する.
上の例ではFaultの子には三つの子要素がある.
- faultcode
- 必須要素.
コードはSOAPで定められた接頭辞をもつ.
- VersionMismatch
- SOAPEnvelopeの名前空間が不正
- MustUnderStand
- サーバが必須ヘッダを理解できない. ヘッダ処理については別の頁にて調査する.
- Client
- 要求電文不正.
- Server
- サーバ側での処理失敗.
- faultstring
- 必須要素. 失敗の概要を記述する.
- detail
- 詳細情報.
回答電文はinvokeメソッドの返り値で取得できる.
Object result = call.invoke(input);
System.out.println("className of result = " + result.getClass().getName());
System.out.println("className of result[0] = " + ((Vector)result).get(0).getClass().getName());
System.out.println("result = " + result);
上記部分の出力は,
className of result = java.util.Vector result.size = 1 className of result[0] = org.apache.axis.message.RPCElement result = [<responceMessage><value>2005-10-22</value></responceMessage>]となっている. RPCElementはSOAPBodyElementを実装しているので,ここからSOAPBodyを取り出して処理することができる. この処理はやはりDOMプログラミングの拡張となるので,割愛した. SOAP MessagingであるのにRPCElementが返ることに違和感がある場合は,MessageContextから回答SOAPEnvelopeを取得することができる.
MessageContext context = call.getMessageContext();
Message res = context.getResponseMessage();
SOAPEnvelope resEnvelope = res.getSOAPEnvelope();
SOAPBodyElement resBody = resEnvelope.getFirstBody();
StringWriter writer = new StringWriter();
XMLUtils.ElementToWriter(resBody, writer);
System.out.println("elementBody = " + writer.toString());
これの出力は以下.
elementBody = <responceMessage><value>2005-10-22</value></responceMessage>SOAPEnvelopeからSOAPBodyを取得した後は,先と同様となる.

