昨日は
2時間で学ぶ今月のJavaホットトピック(1月号)にご来場いただきました皆様ありがとうございました。さて、昨日ご紹介した内容の中で、「
Mash up Award 2nd」で利用できるAPIのうちのひとつ、経路検索Webサービスの「
RailGo」をご紹介しました。おさらいとしてここでそのやり方を紹介していきます。
RailGO APIはSOAPを使ったWebサービスとして提供されています。SOAPを使ったWebサービスはツールさえ対応していれば使用は手軽です。今回は
NetBeans 5.5を使ってWebサービスを利用する方法を紹介します。
Webサービス・クライアントの作成
まず、SOAPを使ったWebサービスを利用する場合にはWSDLというWebサービスの内容を定義したファイルをツールに取り込みます。NetBeansでは「Webサービスクライアント」を作成する事で取り込むことができます。
プロジェクトを選択して、新規の「Webサービスクライアント」を選択します。
Webサービスクライアントの設定で、WSDLを選択してRailGo のWebサービス定義のアドレスである「http://webservice.railgo.jp/expservice04.asmx?WSDL」を入力し、パッケージ名を適当に入力します。この処理の際実際にこのアドレスにアクセスして処理が行われるので、ネットワーク接続にプロクシサーバを利用する場合にはその設定を行ってください。
完了するとこのようにWebサービス参照がプロジェクトにWebサービスの定義が追加されます。
このWebサービスのメソッド定義をドラッグ&ドロップでソースコードに持っていくと(図ではSearchStationというメソッド)、自動的にそのメソッドを呼び出すためのコードを書いてくれます。通常はこれで実行すればすぐ使えるようになるんですが、RailGo ではSOAP通信のヘッダ部分にRailGo 独自の認証情報を送付しなければならなくなっているため、このままでは認証エラーで終了してしまいます。
認証ヘッダの追加
ユーザ認証の方式にWS-Security等の標準的な仕様が利用されていればツールやライブラリ側の設定だけでそれほど苦労しないのですが、今回のRailGo のように独自の方式が採用されている場合には少し苦労を伴います。上記のドラッグ&ドロップして作成したWebサービス呼び出しコードでは、SOAPヘッダに情報を追加する事ができないため、今回はJAX-WSのハンドラ、とよばれる仕組みを使ってヘッダに認証情報を追加する事にします。
ハンドラについては「A little bit about Handlers in JAX-WS」にある図がわかりやすいと思いますが、Web サービスを実行する際に、その途中でメッセージに対して付加的な処理を行う事ができる仕組みです。典型的にはこの方法を利用してWebサービスのログを取得するように利用します。
では早速RailGo 独自認証に対応するハンドラを作る事にします。ハンドラを作るには javax.xml.ws.handler.soap.SOAPHandler インタフェースを実装します。実際に RailGoの独自認証に対応したハンドラが次のソースコードです。
/*
* RailGoAuthHandler, Created on 2007/02/01, 11:21
*/
package quickmashup;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
/**
* @author takayuki
*/
public class RailGoAuthHandler implements SOAPHandler<SOAPMessageContext> {
/**
* SOAPメッセージをハンドルする.
* @param context メッセージコンテキスト.
* @return 処理を継続する場合true、処理をブロックする場合false.
*/
public boolean handleMessage(SOAPMessageContext context) {
// 外向き(クライアント→サーバ)のメッセージか、内向き(サーバ→クライアント)の
// メッセージかを振り分ける.
Boolean outboundProperty = (Boolean) context.get(
MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outboundProperty.booleanValue()) {
return handleOutboundMessage(context);
} else {
return handleInboundMessage(context);
}
}
/**
* 外向きメッセージの処理.
* @param context メッセージコンテキスト.
* @return 処理を継続する場合true、処理をブロックする場合false.
*/
public boolean handleOutboundMessage(SOAPMessageContext context) {
try {
SOAPEnvelope env = context.getMessage().getSOAPPart().getEnvelope();
SOAPHeader header = env.getHeader();
// SOAPヘッダが設定されていなければ追加する
if (header == null) {
header = env.addHeader();
}
// SOAPヘッダに認証エレメントを追加
SOAPHeaderElement he = header.addHeaderElement(
env.createName("Authentication", "",
"http://expart.est.co.jp/ExpService04.asmx"));
SOAPElement usr = he.addChildElement("User");
SOAPElement passwd = he.addChildElement("Password");
usr.setTextContent("mctuser");
passwd.setTextContent("skusnag4");
return true;
} catch (SOAPException ex) {
ex.printStackTrace();
return false;
}
}
/**
* 内向きメッセージの処理.
* @param context メッセージコンテキスト.
* @return 処理を継続する場合true、処理をブロックする場合false.
*/
public boolean handleInboundMessage(SOAPMessageContext context) {
// 何もしない
return true;
}
public boolean handleFault(SOAPMessageContext context) {
// 何もしない
return true;
}
public void close(MessageContext context) {
// 何もしない
}
public Set getHeaders() {
return null;
}
}
ハンドラの実装が終われば、このハンドラが自動的に呼び出されるように設定します。
Webサービスの定義をクリックして、「ハンドラの設定」を選びます。
次にダイアログで先ほど作成したハンドラを選びます。ハンドラの設定が終わったらこの設定を反映させるために一度「プロジェクトの成果物を削除して構築」処理を行っておきましょう。
気を取り直して Webサービスの呼び出し
ではこれで認証は通るはずなので、Web サービスへ追加するパラメータを設定して呼び出してみましょう。
package quickmashup;
import jp.railgo.webservice.AreaType;
import jp.railgo.webservice.Station;
import jp.railgo.webservice.StationType;
/**
*
* @author takayuki
*/
public class Main {
/** Creates a new instance of Main */
public Main() {
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
try { // Call Web Service Operation
jp.railgo.webservice.ExpService04 service = new jp.railgo.webservice.ExpService04();
jp.railgo.webservice.ExpService04Soap port = service.getExpService04Soap();
// TODO initialize WS operation arguments here
java.lang.String stationYomi = "しぶや";
jp.railgo.webservice.AreaType areaType = AreaType.fromValue("Japan");
jp.railgo.webservice.StationType stationType = StationType.fromValue("RailRoad");
int date = 20070201;
// TODO process result here
jp.railgo.webservice.ArrayOfStation result =
port.searchStation(stationYomi, areaType, stationType, date);
for (Station s : result.getStation()) {
System.out.println("駅名: " + s.getName());
System.out.println("よみ: " + s.getYomi());
System.out.printf("%s %s度%d分%f秒\n",
"E".equals(s.getLongitude().getBearing()) ? "東経" : "西経",
s.getLongitude().getDegree(),
s.getLongitude().getMinutes(),
s.getLongitude().getSecond());
System.out.printf("%s %s度%d分%f秒\n",
"N".equals(s.getLatitude().getBearing()) ? "北緯" : "南緯",
s.getLatitude().getDegree(),
s.getLatitude().getMinutes(),
s.getLatitude().getSecond());
}
} catch (Exception ex) {
// TODO handle custom exceptions here
}
}
}
太字にしてあるところが書き換えたところです。stationYomi は駅名の読みがな、areaType は検索地域です。この AreaTypeのように、定数のものは AreaType.fromValueのようなメソッドを利用して名前に対応するインスタンスを取得します(Japan以外には tohokuとか、kinkiなどが選べます)。stationTypeも同様に設定します。RailRoadは鉄道、BusStopならバス停です。次の dateは int型で yyyymmdd となるように設定します。
あとは生成されたコード通り呼び出せば次のような結果が得られます。結果の取り出しは上記のコードを参考にしてみてください。
駅名: 渋谷
よみ: しぶや
東経 139度42分15.900000秒
北緯 35度39分19.300000秒
いかがでしょうか。RailGoのような身近なサービスは何かと組み合わせが思いつくサービスですのでぜひともご活用ください。
Posted by hedepappy on 2月月 07日, 2007年 at 01:57 午後 JST #