Takayuki Okazaki's Weblog
ブログ: 岡崎 - Okazaki's blog
20070227 2007年 2月 27日 火曜日
無料セミナー:今月の2時間で学ぶJava Hot Topic(3月号)
English Translation: (Yahoo!) / (Google)

毎月恒例のセミナーシリーズの3月号「今月の2時間で学ぶJava Hot Topic(3月号)」の詳細な内容が決まりました。今回も2つのトピックですが、まずトップバッターはなにわのJavaエバンジェリスト 谷本さんによる「30分でできる かんたん開発」で、NetBeans Visual Web Packを使ったアプリケーション開発入門編。

そして2つめのトピックは櫻庭さんによる「この世で一番かんじんなのは、ステキなタイミング 〜 Swingのためのアニメーションのすすめ〜」です。ここでのテーマはSwing向けのTiming Frameworkです。個人的には勉強しようしようと思っていてまだ手を付けていなかったところなので興味津々です。

セミナーの日程/場所は次の通りです:

  • 日時: 2007年3月14日(水) 18:30〜20:30 (18:00受け付け開始)
  • 場所: サン・マイクロシステムズ用賀本社 27Fセミナールーム Atrium 11

いつも通り参加は無料ですが事前登録制ですので「申し込みページ」からお早めに申し込みください。



java.net Newsが終了
English Translation: (Yahoo!) / (Google)

個人的にJava系の最新ネタを仕入れるニュースソースとして利用していた java.net Newsが近頃更新されてないなと思ったら、終わってしまうのだそうです。代替のものとしては http://www.planetjava.org が紹介されています。ちょっと残念というか、寂しいですね。

java.net News Discontinued


20070224 2007年 2月 24日 土曜日
むしめがね
English Translation: (Yahoo!) / (Google)

最近虫眼鏡を使って写真を撮るのがちょっと楽しくなってきました。うちのデジカメは悲しい事にすでに製造中止になったNikon D50ですが、昨年勢い余って買ったはいいものの、レンズはレンズキットでついていたAF-S DX Zoom Nikkor ED 18〜55mm F3.5〜F5.6Gだけしか持っていません。コンパクトカメラを使っているよりは楽しいものの、ちょっと物足りない感があります。特に、最近のコンパクトカメラは画素数もそこそこで、少なくとも3倍〜6倍ぐらいのズームができてマクロモード撮影でちっこいものまでわりときれいに写るのに、こちらは一眼デジカメなのに全然太刀打ちできないのです。

悔しいのでレンズを買いたいところですがなかなか予算もありません。しょうがないので、発想を転換して虫眼鏡を使う事にしました。使用した虫眼鏡は100円ショップで売っていたやつです。

Ita - 19

こんなかんじに映ります。思っていたほど悪くないし、フォーカスもカメラ側がやってくれるので十分明るければさほどぶれません、それに独特の風合いがあります。あと、テレコンバータと違って水中に持っていくときも水中用装備を特に換えなくてよいので水中でも気軽に使えます(また、100円の虫眼鏡なのでこわれてもさほど精神的ダメージがありません)。

Tago - 11

こんなのとか、
Tago - 28

こんな感じで水中でもわりと問題なく撮れます。これで気分を良くして最近広角側もこういう風にできないかと考えているんですが、さすがに凹レンズってなかなか100円ショップでは売っていないし、それは無理そうですね・・・。




20070222 2007年 2月 22日 木曜日
ネトビ
English Translation: (Yahoo!) / (Google)

NetBeans(ネットビーンズ)って長過ぎはしないけど日本語の語感からすると微妙に長い名前な気がするので、McDonalds(マクドナルド)をマクドと略すような雰囲気で「ネトビ」と呼んではどうか、なんていうことをこの間片貝さん町田さんらと飲みながら話していました。少なくとも個人的にはとても気に入っています。

ただ、そういう風にある国独自の呼び方があるのかどうかはちょっと疑問として残っていました。そこで何でも漢字に翻訳してしまいそうな勝手なイメージを持っている中国語でどうなっているかを、中国語版のWikipediaでしらべてみました。

すると、NetBeansという単語はすべてNetBeansであり、特別漢字が割り当てられているという様子は見当たりません。残念。ちなみにNetBeans Platformは「NetBeans 平台」
になるようです。



先週の丸山先生レクチャーシリーズ: Project Tangoプレゼンの舞台裏, その2
English Translation: (Yahoo!) / (Google)

さて前回に引き続き丸山先生レクチャーシリーズでの岡崎の悪戦苦闘ぶりをご紹介します。さて、ちょっと横道にそれますが櫻庭さんが「今日のプレゼン準備 その1」というのを紹介されています。とても参考になります。

会場チェック・・・。岡崎はそういうのほとんど気にしたことはありませんでした。もちろん、収容人数と時間帯ぐらいは事前に確認しておきますが、部屋の形状とか天井の高さ、プロジェクターの種類までは全く・・・。せいぜいネットワーくがあるかどうかとかしか確認していませんね。反省。

さて、前回はPowerShellのコマンドプロンプトを

PS ~\デスクトップ>  

のような感じに設定して満足したところで終わりました。さて、今回はもうちょっとProject Tango的な事をする準備段階です。

.NET 3.0などなどを入れる

Project TangoのデモつまりJava側のアプリと .NET側のアプリがWebサービスでつながっている様子をデモンストレーションするには Javaと .NET両方の設定がいります。まずは .NET側の設定をご紹介します。

Project Tangoで相互運用できる .NET環境というとバージョン 3.0です。これは記憶が正しければ Windows Vistaに入っているはずですが、ウチにはまだVistaが届かないので (MicrosoftのXPからの優待アップグレードを注文したはずなんですが・・・)、ひとまずXP Proでデモすることにしました。そうすると標準ではそういうのは入っていないので次の物をいれます。

昨年末のSun Software Showcaseでご紹介したときにはデモは完全に不発で、SvcUtil.exeがClassNotFoundExceptionみたいなログをはいて異常終了という感じでしたが、よくよく観察するとWindows SDKのバージョンが古かったようです。当時、情報も全くない、というかMSDNの歩き方がよくわからず途方に暮れていました。

さて、今回はなんとかその問題もないバージョンを手に入れられたのか問題なく動きました。

Visual Studio 2005を入れる

コマンドラインだけでデモするならば上記だけでも良かったんですが、もうすこしデモに迫力を出したかったのでVisual Basic 2005を使う事にしました。幸いにも約10年Visual Basicを触らないうちにExpress Editionとかいう無料で使えるバージョンが出ていたのでそれを使う事にしました。

KB912817を入れる

もうなぜこれが必要だったのかもよく覚えていませんが、WS-AtomicTransactionのデモがうごかない・・・。というのがよく身にしみてきた頃にこれを入れろって指示をMSDNで見つけた気がします。

はい。ここまでが.NET関連でインストールしなければならなかった記憶のあるものの列挙です。正直なところ今回デモを用意するのにこれほど苦労するとは全く想定していなかったというか、相当油断していたのできちんとしたURLのメモすら存在しません・・・。

Project Tangoを設定する

Project Tango側というか、Java側は勝手知ったる、でそれほど問題なくスムースに進みました。デモの段階で必要だったのはGlassFish v2NetBeans 5.5.1WSITプラグインWSITでしたが、それぞれベータ段階に入りつつある状況で、まだところどころ怪しいところがあったのでそれぞれ2週間前ぐらいからきちんと動きそうなバージョンをそろえておきました。

  • GlassFish v2を入れる (このときは GlassFish v2 b35)
  • NetBeans 5.5.1を入れる (このときは NetBeans 5.5.1のDaily Build 200702070600)
  • WSITプラグインを入れる (このときは 2月7日版)
  • WSITを入れる (このときは 2月2日版)

なぜ手こずったか

今回デモしようと思ったのはProject Tangoで実装されている主な機能のうちトランザクションの機能でした。これは見た目にも何となくわかりやすい物を作れそうだし、設定も (少なくともJava側というか、トランザクションに入るビジネスロジックを実装するだけなら) 簡単で、これならまあ、いいかな〜。という風に思っていました。それがプレゼンの2日前〜18時間前までです。

とりあえず、VBのプログラムやデモシナリオができて、チェックしてみたらどうやら Java -> .NET で接続がうまく行かないというログがでていましたが、18時間前の段階では、どうせクライアントファイアウォールの設定とか、ネットワーくの設定がおかしいんだろうと思っている程度でした。

ところが pingも通るし、HTTPも通るように設定してもうまく行く気配がありません。ここで少しずつ暗雲がたちこめてきました。そしてエラーメッセージ等からたどっていってようやく今起こっている問題の原因がWS-AtomicTransactionではなくて、WS-Corrdination側でのエラーであるという事でした。

WS-AtomicTransactionは原子的トランザクションをサポートする仕様ですが、WS-Coordinationは分散しているトランザクションを解決するための調整の仕様で、
トランザクションに参加しているシステムはそのトランザクションを調整する調整者にあらかじめ参加を宣言します。今回の場合、どうやらここがうまく行っていないようでした。

Windows側に置けるWS-AtomicTransactionの設定  

さて、原因が分かったので早速対処をする事にしました。それはたしかプレゼンの12時間前、午前3時頃だったと思います。もうこの段階になるとProject Tangoのメーリングリストやフォーラムに問い合わせてやり方を聞くのもそろそろ微妙な段階でした。(今考えればダメもとで聞いておいても良かったかもしれません)

とりあえずいろいろと調べてみると次の手順が必要であるという事はわかりました。

  • WS-ATのUIを有効化
    • cd %PROGRAMFILES%\Microsoft SDKs\Windows\v6.0\Bin
    • regasm.exe /codebase WsatUi.dll
  • SSL証明書を作る
    • makecert -r -pe -n "CN=なんちゃら" -eku 1.3.6.1.5.5.7.3.1 -ss my -sr localmachine -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12
  • コンポーネントサービスで「My Computer」を選んでプロパティを選択
  • 分散トランザクションをネットワーく越しで使えるように有効化
  • WS-ATもネットワーく越しを許可
  • WS-ATにSSL証明書を設定

とりあえずここまではなんとか調べてできありました。ところがWS-ATをネットワーく越しでも有効にする事ができませんでした、その原因は結局わからず、プレゼン当日を迎えました。

以上のようなかんじで、やっぱりプレゼンの事前準備(特にデモ) ってかなり前からやっとかないと危ないな〜っていうのは改めて感じました。 今後は反省してきちんと準備するようにしたいところです (とはいっても急に仕事がいっぱいになると、それもなかなか厳しかったりしますが・・・ (;_;)。



20070220 2007年 2月 20日 火曜日
先週の丸山先生レクチャーシリーズ: Project Tangoプレゼンの舞台裏, その1
English Translation: (Yahoo!) / (Google)

先週金曜日(2月16日)に行われた「丸山先生レクチャーシリーズ第4回:Webサービス/SOAの現在」にて岡崎のプレゼン「Project Tangoで本格化する.NET/Java Webサービス相互運用」に参加いただいた皆様ありがとうございました。

このネタはホットトピックセミナ(11月号)Borland Developer CampSun Software Showcaseとご紹介するのは今回で4回目になりますが、今回はこれまでのアンケート等で要望の多かったデモを中心にやる事にしようと思っていました。結果的に、最後微妙にうごかなかったりとか、tcpmonのダンプをご紹介して説明しようとしていたのを忘れていたとか不備がありましたが今回はその舞台裏をご紹介します。

デモの体裁にこだわろう

デモはSun Software Showcaseの時にも少しやろうとしていたり、それ以外にも暇を見つけてちょっとずつ触っていたので、まあ、手順はだいたい問題ないだろうと思っていました。それよりも問題はWebサービスのデモがあまりにも地味な事でした。

たとえばWS-ReliableMessagingで高信頼性メッセージングができましたー!なんて言っても、マシンが2台あって、LANケーブルをぶちっと抜くようなデモンストレーションでもしないと通信中のXMLダンプをご紹介しても、WS-ReliableMessagingとかTCPのSYN/ACKの仕組みを知らない方にはなかなかイメージが伝わらない。あるいは別のデモとしてセキュリティ系の設定はある程度お膳立てが面倒な上、それを一つ一つ説明するには時間が足りない。 

そんなこんなでまず基本的なところで、.NET 3.0でWebサービス参照を作るところから紹介する事にしました。 Project Tangoの設定をしたWebサービスを .NET 3.0上のアプリ(VC# 2005とかVB 2005)で使えるようにするには .NET 3.0流のWeb Referenceを作ります。これは標準的には SvcUtil.exeというのを使います。

> SvcUtil.exe WSDLのURL

これを実行すると結果としてWeb参照のクラスファイル(デフォルトではC#用)と設定ファイルが生成されます。ここでファイルができたなーってわかりやすくするために、デスクトップ上でコマンドを実行したかったのですが・・・

PowerShellプロンプトのフルパス表示をなんとかしたい

Windowsのコマンドプロンプトでも、最近新しくできたらしいPowerShellという標準のシェルを使っても、基本的にプロンプトのパス表示はフルパスになります。そうすると、デスクトップ・フォルダ上で作業をしようとすると「C:\Documents and Settings\<ユーザ名>\デスクトップ」という長ったらしい表示になります。SvcUtil.exe を実行するときにつける URLも例えば http://192.168.2.1:8080/HelloService/Hello?wsdl のように同様に長ったらしく、どこまでがコマンドか、とかもわかりにくくなってしまいます。

また、他の観点として、知り合いに見せたり、会場でデモをするだけなら良いんですが、スクリーンショットをWebに載せたりする場合に、そのデモ機のOSアカウント名がばれてしまうのはセキュリティ上好ましくない、という考え方もあるのでなるべくこのようにアカウント名が推測できるような設定はやめたいと考えました。

まあ、コマンドプロンプトで

> set prompt=$g

ぐらいにすれば簡単に回避できるのですがそれはそれで素っ気ないので、PowerShellで UNIXライクにホームディレクトリ以下は「~」(チルダ)で表示させるようにしようと思いました。

PowerShellプロンプトのホーム表示を ~にする

いろいろ調べてみると、PowerShellでは promptという関数を定義すればプロンプトの表示を変更できる事がわかりました。また、それを bシェルの .profileのように $home/My Documents/WindowsPowerShell/profile.ps1 に書いておけば良いということもわかりました。そうとわかれば早速 prompt関数を定義するだけです。内容は次のような感じです。

 

function prompt {
$(
$loc = $(get-location);
if ($loc.path.startsWith($home)) {
"PS ~" + $loc.path.substring($home.length,
$loc.path.length - $home.length) + "> "
} else {
"PS " + $(get-location).path + "> "
}
)
}

 

まあこの定義が効率的かどうかとかはおいておいて、とりあえずデモに耐えうるだろうということは確認できたのでこれを使う事にしました。さて、UNIXならこれでおしまいですがたぶん .NET 3.0の事情だと思うのですがセキュリティの制限でPowerShell上で実行されるスクリプトとかはデフォルトでは全て署名されていなければ実行してもらえません。その設定を変更する方法もありますが、ここは流儀に従って署名をすることにします。

とはいっても正式な証明書をVeriSignとかにお願いして作ってもらうほど大げさな事ではないのでオレオレ証明書ですませる事にします。

まずローカルマシン上のルート証明を作ります。 

PS> makecert -n "CN=なんちゃら Root" -a sha1 -eku 1.3.6.1.5.5.7.3.3 -r -sv root.pvk root.cer -ss Root -sr localMachine

次に、個人証明を作ります。

PS> makecert -pe -n "CN=なんちゃら" -ss MY -a sha1 -eku 1.3.6.1.5.5.7.3.3 -iv root.pvk -ic root.cer 

これを使ってスクリプトに署名します。

PS> $cert = @(Get-ChildItem cert:\CurrentUser\My -codesigning)[0]
PS> Set-AuthenticodeSignature profile.ps1 $cert

 さてあとはPowerShellを再起動するだけ。最初の一回はこれを実行するか、と聞いてきますがそこで今後も実行のように選べば良い訳です。

Windows PowerShell

こんな感じでようやく一つのお膳立てが終わりました。続きはまた次回。



20070208 2007年 2月 08日 木曜日
マッシュアップ2 : RailGoで駅検索その2
English Translation: (Yahoo!) / (Google)

前回のエントリ「マッシュアップ2 : RailGoで駅検索」ではJAX-WSのハンドラという仕組みを使ってSOAP通信にヘッダを追加するような例を紹介しました。ここで一つお詫びですが、サンプルで紹介したRailGoAuthHandlerというクラスの一部がコピペする段階で消えてしまっていたようで、そのままではコンパイルできないようになっていました。現在は訂正してありますのでご確認ください。(クラス宣言のpublic class RailGoAuthHandler implements SOAPHandler<SOAPMessageContext>のところの <SOAPMessageContext>という部分が消えていました・・)

 さて、今回はマッシュアップ向けというよりはJAX-WSのハンドラについてもう少し詳しくご紹介しておきます。前回のサンプルではRailGoサービスを利用するためのユーザ名とパスワードは固定でした。今回のMash up Award 2ndに応募される作品をとりあえず仕上げるという場合には問題にならないのですが、実際のビジネスアプリケーションではユーザ名やパスワードが固定と言うことはまれで、そういった情報は実行時に決定されることがほとんどです。

今日はそのような場合にどうやってハンドラに情報を渡していくかという方法をご紹介します。

どのようにハンドラが決定されるのか 

ではまず前回ご紹介したように、NetBeansでハンドラを設定した場合にはどのようにハンドラがサービスに結びつけられ、生成され、呼び出されるのかを見てみましょう。
Mash up Award 2nd, How to use RailGo API - 6 of 6
NetBeansの場合、ハンドラの設定を行うとその情報はXMLファイルに書き込まれます。

<?xml version="1.0" encoding="UTF-8"?>
<jws:handler-chains xmlns:jws="http://java.sun.com/xml/ns/javaee">
    <jws:handler-chain>
        <jws:handler xmlns="http://java.sun.com/xml/ns/javaee">
            <jws:handler-class>quickmashup.RailGoAuthHandler</jws:handler-class>
        </jws:handler>
    </jws:handler-chain>
</jws:handler-chains>

 このXMLファイルとServiceインスタンスであるExpService04は、アノテーションによって結びつけられます。次はWebサービスクライアントとして生成されたServiceクラスの宣言部分です。

/**
 * 駅すぱあと 路線検索Webサービス
 *
 * This class was generated by the JAXWS SI.
 * JAX-WS RI 2.0_01-b59-fcs
 * Generated source version: 2.0
 *
 */
@WebServiceClient(name = "ExpService04", targetNamespace = "http://expart.est.co.jp/ExpService04.asmx", wsdlLocation = "http://webservice.railgo.jp/expservice04.asmx?WSDL")
@HandlerChain(file = "ExpService04_handler.xml")
public class ExpService04 extends Service

 この@HandlerChainアノテーションによって、ハンドラの設定ファイルと結びつけが行われます。この結びつけはExpService04のインスタンスが生成された時点でその情報が読み込まれ、実行時には設定したRailGoAuthHandlerが呼び出されます。

呼び出すハンドラを動的に変更する

上記のようにあらかじめハンドラを設定しておくというのも便利なんですが、今回のようにハンドラに動的に値を設定したり、ハンドラ自体を別の物にしたりしたいというケースはよく考えられます。JAX-WSではこのような場合にサービスごと、ポートごと、呼び出しごとにハンドラを変更する事ができるようにHandlerResolverという仕組みを提供しています。

HandlerResolverは javax.xml.ws.Serviceに設定されている、どのハンドラを利用するのかを解決するためのインタフェースです。呼び出すハンドラを動的にかえたいのであれば、このHandlerResolverを変更すれば良いのです。なお、先ほど説明したNetBeansでハンドラを設定した方法の場合、実はこのHandlerResolverが自動的に設定され、RailGoAuthHandlerが呼び出されていたのでした。

ではその説明の前に、RailGoAuthHandlerをユーザ名、パスワードを変更できるようにすこし改造しておきましょう。ここでは新しいクラス名をRailGoAuthHandler2にしています。

import java.util.Set;
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 RailGoAuthHandler2 implements SOAPHandler<SOAPMessageContext> {
    /** ユーザ名. */
    private String user;
    /** パスワード. */
    private String password;
   
    /**
     * コンストラクタ.
     * @param user ユーザ名.
     * @param password パスワード.
     */
    public RailGoAuthHandler2(String user, String password) {
        this.user = user;
        this.password = password;
    }
   
    /**
     * 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(user);
            passwd.setTextContent(password);
           
            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;
    }
}

 変更点はコンストラクタにユーザ名とパスワードを設定できるようにしたところです。では次に本題のHandlerResolverを実装してみましょう。HandlerResolverにはgetHandlerChainというメソッドだけが定義されており、引数にはポートの情報が渡されます。つまり、ハンドラチェインはポートごとに切り替えもできるし、この情報を無視すればサービスごと、というように切り替える事ができる訳です。

public class AuthHandlerResolver implements HandlerResolver {
    /** 既存のリソルバ. */
    private HandlerResolver resolver;
    /** ユーザ名. */
    private String user;
    /** パスワード. */
    private String password;

    /** コンストラクタ. */
    public AuthHandlerResolver(HandlerResolver resolver,
            String user, String password) {
        this.resolver = resolver;
        this.user = user;
        this.password = password;
    }

    /**
     * ハンドラチェインを取得.
     * @param portInfo ポートの情報.
     * @return ハンドラチェイン.
     */
    public List<Handler> getHandlerChain(PortInfo portInfo) {
        List<Handler> list;
        if (resolver != null) {
            list = resolver.getHandlerChain(portInfo);
        } else {
            list = new ArrayList<Handler>();
        }

        // RailGoAuthHandler2を追加
        list.add(new RailGoAuthHandler2(user, password));

        return list;
    }
}

こんな感じです。なお、ハンドラリゾルバはServiceに対して一つしか設定できないようなので、ここでは既に設定済みのリゾルバを設定してその設定も読み込みするようにしています。あと、このハンドラチェインはWebサービス呼び出し時点で確定すると、そのスナップショットコピーがとられ、連続して別のWebサービスが呼び出された場合でももとの呼び出しはその変更の影響を受けません。

さて、ではあとはこれをサービスに設定するだけです。

jp.railgo.webservice.ExpService04 service = new jp.railgo.webservice.ExpService04();

service.setHandlerResolver(
        new AuthHandlerResolver(
            service.getHandlerResolver(), "mctuser", "skusnag4"));


jp.railgo.webservice.ExpService04Soap port = service.getExpService04Soap();

java.lang.String stationYomi = "しぶや";
jp.railgo.webservice.AreaType areaType = AreaType.fromValue("Japan");
jp.railgo.webservice.StationType stationType = StationType.fromValue("RailRoad");
int date = 20070208;
jp.railgo.webservice.ArrayOfStation result = port.searchStation(stationYomi, areaType, stationType, date);

このように、Service#setHandlerResolverを呼び出せば設定する事ができ、今回の場合のようにユーザ名、パスワードも動的に設定する事ができるようになりました。なお、注意点としてはこの設定は上記で言う ExpService04Soapのインスタンスを service.getExpService04Soap()で生成する前に行わなければならないという点です。この後に呼び出しても反映されません。

以上のようにWebサービス・ハンドラに対して動的に変更を加える事ができるようになりました。



20070205 2007年 2月 05日 月曜日
5分でわかる今週のJavaホットトピックが始まりました
English Translation: (Yahoo!) / (Google)
既にご覧頂いた方もいらっしゃるかもしれませんが、今週より5分でわかる今週のJavaホットトピック・ブログを開始しました。このブログは毎週、その週にホットなおもしろいJava関連情報をお届けするブログです。原則として毎週更新していきますのでよろしくお願いいたします。


20070204 2007年 2月 04日 日曜日
ブログのレイアウト/デザインを変更
English Translation: (Yahoo!) / (Google)
このブログを始めてからページのレイアウト/デザインはずっと同じでした(まあ、ちょこちょこいじってはいましたが)。
もともとのデザインで気に入らなかったところがあって、それは文字が見にくいということでした。フォントサイズも小さいし (元のデザインでは文字は9ポイント、今使っているのが11ポイントの文字)、画面幅いっぱいにべったりと文章が流し込まれてしまうので読みづらい。そしてきっと目にも悪い。
そんなこんなでいろいろといじっているうちにこれならいっその事・・・。ということで全体的に新しいデザインに作り直しました。
ここで困ったのはInternet Explorerでの表示でした。最初、Firefoxで確認をしてだいたいいけそうかな〜、とか思っていて念のためにIEで表示してみたら全然ダメ・・・。そこからの試行錯誤は大変で、タグを直したりスタイルシートを直したりと一瞬IE非対応ぐらいにしようかなと思うぐらいでしたが、IEでご覧頂いている方も多いようなのでそこはぐっとこらえて調整、調整、調整・・・。
ただ、全体を中央寄せにしたかったんですが、なぜかIEでは margin: 0 auto; とかやってもうまく行かず、原因もよくわからないので挫折しました。
もう一つ大変だったのは過去のエントリーで、幅を目一杯使っていたもの。それも全部画像の大きさとか、PREタグのサイズとかを調整しました。
(IEでwidthを指定しないとoverflow属性が無視されるというのには泣けてきました)
さて、そんなこんなで出来上がった新デザインですがいかがでしょうか?でも一応、旧デザインのページも残しておきます。

Before

Old Blog Design/Layout before Feb 3rd

After

New Blog Design/Layout from Feb 3rd


20070201 2007年 2月 01日 木曜日
マッシュアップ2 : RailGoで駅検索
English Translation: (Yahoo!) / (Google)
昨日は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サービスクライアント」を作成する事で取り込むことができます。
Mash up Award 2nd, How to use RailGo API - 1 of 6
プロジェクトを選択して、新規の「Webサービスクライアント」を選択します。
Mash up Award 2nd, How to use RailGo API - 2 of 6
Webサービスクライアントの設定で、WSDLを選択してRailGo のWebサービス定義のアドレスである「http://webservice.railgo.jp/expservice04.asmx?WSDL」を入力し、パッケージ名を適当に入力します。この処理の際実際にこのアドレスにアクセスして処理が行われるので、ネットワーク接続にプロクシサーバを利用する場合にはその設定を行ってください。
Mash up Award 2nd, How to use RailGo API - 3 of 6
完了するとこのようにWebサービス参照がプロジェクトにWebサービスの定義が追加されます。
Mash up Award 2nd, How to use RailGo API - 4 of 6

この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&lt;SOAPMessageContext&gt; {
/**
* 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;
}
}
ハンドラの実装が終われば、このハンドラが自動的に呼び出されるように設定します。
Mash up Award 2nd, How to use RailGo API - 5 of 6
Webサービスの定義をクリックして、「ハンドラの設定」を選びます。
Mash up Award 2nd, How to use RailGo API - 6 of 6
次にダイアログで先ほど作成したハンドラを選びます。ハンドラの設定が終わったらこの設定を反映させるために一度「プロジェクトの成果物を削除して構築」処理を行っておきましょう。

気を取り直して 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のような身近なサービスは何かと組み合わせが思いつくサービスですのでぜひともご活用ください。



過去の記事
« 1月 2007 »
    
2
3
6
7
9
10
11
12
13
14
15
16
17
18
19
21
23
25
26
28
   
       
今日
Click me to subscribe このブログを購読(RSS)
検索

このブログ著者について
ソフトウエア・インフラストラクチャー・ソリューション本部のソリューション・アーキテクトでした(2008年8月退職)。 本業はSOAソリューションならびにSun Java CAPSによるソリューションのプリセールスをお手伝いするエンジニア、とJavaエバンジェリストグループに参加してセミナーに行ったり、趣味のプログラミング・ネタをこのブログで紹介したりしていました。現在は、ふらふらとwatermint.orgで活動中〜。
リンク
 
SunホットトピックPodcast - SunホットトピックPodcast
 


 

Today's Page Hits: 412