デベロッパーズコーナー:Javaプログラミングを極める「JAXM(その2)」
2003年03月31日作成
Javaプログラミングを極める
第6回:JAXM(その2)
(株)日本ユニテック
太田 純
<この記事はDigital Xpress 2002 Vol.12(12-1月号)に掲載されたものです>
今回は前回に引き続き、SOAPを利用したメッセージングAPIであるJAXMについて扱います。今回扱うのはクライアントサイドのプログラミングです。 |
Java API for XML Messaging (JAXM) は、XMLデータをメッセージとして送受信するためのAPIです。本連載の前回の記事ではJAXMのサーバサイドプログラミングについて扱いました。JAXMのサーバプログラミングは、javax.xml.messaging.JAXMServletクラスの派生クラスを使って作成します。そのクラスにおいてonMessageメソッドに処理を記述すれば、その処理がWebサービスのメソッドとして公開されます。
JAXMによるWebサービスの利用
前回、例として挙げたのは、クライアントが注文可能になった新商品を問い合わせ、サーバが商品リストを返却するものでした。クライアントが送出するメッセージをリスト1に、サーバが応答するメッセージをリスト2に示します。では、サーブレットで記述したWebアプリケーションからJAXMで作ったWebサービスを呼び出すコードを書いてみることにしましょう。完全なリストはリスト3に示します。JAXMでWebサービスを利用するには、サーバとの接続を表すSOAPConnectionオブジェクトと、送信するメッセージを表すSOAPMessageオブジェクトを作成します。これらのクラスは両方ともjavax.xml.soapパッケージに含まれています。
SOAPConnectionFactory scf
=
SOAPConnectionFactory.newInstance();
SOAPConnection connection
=
scf.createConnection();
MessageFactory mf
=
MessageFactory.newInstance();
SOAPMessage message = mf.createMessage(); |
このコードに示されているとおり、SOAPConnectionとSOAPMessageの2つのオブジェクトは両方とも以下のような2段階の手順で作成します。
1.ファクトリークラスのstaticなメソッドnewInstanceを呼び出し、ファクトリークラスのオブジェクトを作成
2.ファクトリークラスのcreateXXX()メソッドを呼び出して目的のオブジェクトを作成
送信するメッセージを完成させるには、SOAPMessageオブジェクトから順に下位構造をたどって必要な要素やテキストを追加していくか、またはファイルなどから読み込んでjavax.xml.transform.Sourceオブジェクトを作成してから、javax.xml.soap.SOAPPartクラスのsetContentメソッドで内容を設定します。リスト3のソースでは、下位構造をたどって作成する方法を使いました。SOAPMessageオブジェクトは、内部的にSOAPPart、SOAPEnvelope、SOAPBodyとつながる階層構造を持っています。
SOAPPart soapPart = message.getSOAPPart();
SOAPEnvelope envelope
=
soapPart.getEnvelope();
SOAPBody body = envelope.getBody(); |
メッセージの作成方法については前回の記事も参照してください。メッセージが作成できたら、SOAPConnectionクラスのメソッドcallを呼び出し、その後接続を切断します。
SOAPMessage reply
=
connection.call(message, HOST_URL);
connection.close(); |
callメソッドの引数に送信するメッセージと目的のサービスのURLを渡すと、実際にサービスが呼び出され、サーバが応答してきたメッセージがSOAPMessageオブジェクトとして返却されます。
JAXMとXSLT変換の連携
応答メッセージとして受け取ったSOAPMessageオブジェクトは、メッセージを作成したときと同様に階層構造をたどって内容を読み取ることができますが、以下の手順によってjavax.xml.transform.Sourceオブジェクトを取得すると、XSLT変換に利用することができます。
SOAPPart part = message.getSOAPPart();
Source s = part.getContent(); |
ここで、リスト4のXSLTデータを適用して、受け取ったSOAPメッセージをHTMLに変換した結果は図1のようになります。リスト3の(B)の部分に示したように、SOAPメッセージをXSLT変換に渡すのは非常に簡単に行えます。
【図1:リスト3のプログラムの実行例】
ここで注意を一点述べておきましょう。このようなサーブレットでXSLT変換を行う場合、HTTPレスポンスに設定するコンテントタイプ(リスト3の(A)の部分)と、XSLT変換によって取得するXMLデータのエンコーディング(リスト4のxsl:output要素)を一致させる必要があります。このサンプルでは、両方ともエンコーディングがShift_JISになるように設定しました。この設定が異なっていると正しいデータがクライアントに送られなくなってしまいます。
XSLTファイルのxsl:output要素を使う代わりに、TransformerクラスのsetOutputPropertyメソッドを使うこともできます。Transformerオブジェクトをtとすると、以下のコードによって、変換したXMLデータのエンコーディングを指定できます。
t.setOutputProperty("encoding", "Shift_JIS"); |
XSLTファイル内で出力するデータのエンコーディングを指定していない場合は、transformメソッドを呼び出す前に、setOutputPropertyによってエンコーディングを設定してください。xsl:output要素とsetOutputPropertyメソッドの両方でエンコーディングが指定されていた場合は、setOutputPropertyメソッドの指定のほうが有効になります。
エラー処理
このサンプルでは記述していませんが、サーバ側でエラーが検出された場合、SOAPのフォルトメッセージが返却されてきます。それで、XSLTを使う場合はSOAP-ENV:Fault要素に対する処理も記述しておくべきです。このサンプルのようにフォルト関連の要素に関する処理を記述していない場合でも、デフォルトのテンプレートが使われるので、フォルトメッセージを読み取ることはできます。デフォルトのテンプレートは要素については何も出力せずに子ノードの処理に移り、テキストノードについてはそのまま文字列を出力します。
階層構造をたどってデータを読み取る場合は、SOAPBodyクラスのhasFaultメソッドによりエラーが生じたかどうかを確認します。受け取った応答メッセージの変数名をreplyとすると、以下のようなコードになります。
SOAPPart soapPart = reply.getSOAPPart();
SOAPEnvelope envelope
= soapPart.getEnvelope();
SOAPBody body = envelope.getBody();
if(body.hasFault())
{
// エラー処理
}
else
{
// 正常時の処理
} |
2回にわたってSOAPを使ったメッセージングAPIであるJAXMについて扱ってきました。それほど詳細な説明はしていませんので、理解しにくい部分も多くあったかもしれません。本誌編集部では、Webサービスについて扱った書籍「SOAP/UDDI/WSDL
Webサービス技術[基礎と実践]徹底解説」を技術評論社から出版いたしました。この書籍では、SOAP、UDDI、WSDLについての基本を押さえるとともに、.NETとJavaによるWebサービスプログラミングについて実例を挙げて説明しています。今回扱ったJAXMの詳細についてもこの本からさらに学んでいただくことができます。
【リスト1 : 要求メッセージの例】
<?xml version="1.0"
encoding="utf-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<RequestNewItemList
xmlns="http://soundshop.utj.co.jp/shema/2002/"
/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope> |
【リスト2 :応答メッセージの例】
<?xml version="1.0" encoding="utf-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<RequestNewItemListResponse
xmlns="http://soundshop.utj.co.jp/shema/2002/">
<RequestNewItemListResult>
<item
catalogNo="9n9r-0003">
<name>
なんか不思議な胸騒ぎ</name>
<price>1200</price>
</item>
</RequestNewItemListResult>
</RequestNewItemListResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
|
【リスト3:Unitec Sound Shop Client Serv.java】
import java.io.*;
import java.util.*;
import javax.xml.soap.*;
import javax.xml.messaging.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
public class UnitecSoundShopClientServ extends HttpServlet
{
private static final String
HOST_URL
=
"http://unitec-denki.utj.co.jp:8080/UnitecSoundShop/UTSound";
private static final String
SCHEMA_URL
=
"http://soundshop.utj.co.jp/shema/2002/";
private static final String
XSLT_URL
=
"http://unitec-denki.utj.co.jp:8080/UnitecSoundShopClientServ/UTSSClient.xsl";
public void doGet(HttpServletRequest
request, HttpServletResponse response)
throws
IOException, ServletException
{
response.setContentType("text/html;
charset=Shift_JIS"); ←(A)
PrintWriter
pw = response.getWriter();
try
{
SOAPMessage
reply = sendJAXMMessage();
TransformerFactory
tf = TransformerFactory.newInstance();
Transformer
t = tf.newTransformer(new StreamSource(XSLT_URL));
t.transform(reply.getSOAPPart().getContent(),
new StreamResult(pw)); ←(B)
}
catch(Exception
ex)
{
pw.println("<html><body><p>");
pw.println(ex);
pw.println("</p></body></html>");
}
}
public SOAPMessage sendJAXMMessage()
throws
SOAPException
{
SOAPConnectionFactory
scf = SOAPConnectionFactory.newInstance();
SOAPConnection
connection = scf.createConnection();
MessageFactory
mf = MessageFactory.newInstance();
SOAPMessage
message = mf.createMessage();
SOAPPart
soapPart = message.getSOAPPart();
SOAPEnvelope
envelope = soapPart.getEnvelope();
SOAPBody
body = envelope.getBody();
Name
name = envelope.createName("RequestNewItemList",
"u", SCHEMA_URL);
SOAPBodyElement
bodyElement = body.addBodyElement(name);
SOAPMessage
reply = connection.call(message, HOST_URL);
connection.close();
return
reply;
}
} |
【リスト4:UTSSClient.xsl】
<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
version='1.0'
xmlns:u='http://soundshop.utj.co.jp/shema/2002/'
exclude-result-prefixes="u"
>
<xsl:output method="html"
encoding="Shift_JIS" />
<xsl:template match="/">
<html>
<head>
<title>Unitec Sound Shop 新着情報</title>
</head>
<body>
<h1>Unitec Sound Shop 新着情報</h1>
<p>新規予約可能商品を紹介します。</p>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="u:RequestNewItemListResult">
<table border="1">
<tr>
<th>商品番号</th>
<th>商品名</th>
<th>価格</th>
</tr>
<xsl:apply-templates/>
</table>
</xsl:template>
<xsl:template match="u:item">
<tr>
<td><xsl:value-of
select="@id"/></td>
<td><xsl:value-of
select="u:name"/></td>
<td><xsl:value-of
select="u:price"/></td>
</tr>
</xsl:template>
</xsl:stylesheet> |
関連サービス
IT技術およびIT製品の可用性調査・検証業務