ワタシには2,3年前からずっと解けないでいた謎があった。
それは,「Web Service Developer Packって何だ!?」というものである。
ダウソして解凍する。あるいは最近は生意気にもインストーラがついている。で!?あとどう使うのヨ!・・・と思っていたら,NetBeans.orgのチュートリアルに直撃記事が!これに励まされてやってみることにしてやってみた。まあ・・・長いので書き下ろしにしましょう。
Webサービスって何だ!?二年くらい前にそればかり考えていた時期がある。そこでWeb Service Developer Packというものをダウンロードして展開してみたが,どう使うのか全然わからなかった。そのときは確か,パックの中にTomcatが入っていたはずだ。
最近NetBeans3.6でAxisをいとも優雅に動かせるようになった。そのあとNB4.0になってかなり必死こかされたがこれでも何とか動いた。さてそうなると再びWSDPに挑戦である。
まず,最新のJWSDPをダウソしてくる。jwsdp-1_5-windows-i586.exe というものが落ちてきた。これをダブルクリックしたところ,なんとインストーラだったのでビックリした。昔は無愛想な圧縮ファイルで展開すると無愛想なフォルダが一個できてそれであと何,というものだったが・・・
インストーラはインストールの場所やJavaの場所などを聞いてくる。今度はJDK5にしたゼッ。いや最初は1.4にしたんだけどあとからNetBeans.orgのチュートリアルで5でもイケることがわかったんで改めて5で入れなおしたのサ。
そしてこのインストールで大事な設定があった。それは,Webコンテナは何にしますか?ということだ。
昔は,JWSDPには専用Tomcatが入っていたはずだ,と言った。今はSun App ServerのTomcat部分か,専用のTomcatかを選ぶようになっている。専用Tomcatを使うことにした。
なぜか? TomcatならNB4で動かせるんだヨ。あくまでNetBeans上でやる気でいる。
専用Tomcatは別途ダウンロードしてくる。
http://java.sun.com/webservices/containers/
というサイトから,Sun App Serverにするか,WSDP専用のTomcatにするか,選んでダウソ。
tomcat50-jwsdp.zip
というファイルをもらってきて,展開しておく。できるのは,tomcat50-jwsdp というディレクトリがひとつゴロンと。c:¥tomcat50-jwsdp のように配置しておく。
こうしておいて,JWSDPのインストールウィザードで「Webコンテナを指定してください」という画面が来たら,このディレクトリを指定してやればよい。
これでWSDP側の準備は,オケだ。
以前NB3.6でやろうとして失敗したことだ。理由はなんだっけエラーだったんだヨ。そのときはTomcatのバージョンは4だった。今度5ではどうだ?
やってみる。「Runtime」ウィンドウで,「Server Registory」->「Tomcat5 Server」を右クリックして「Add New
Server」を選ぶ。
図はすでに追加したあとにショットだけ参考に撮ったものです。
サーバの設定ウィンドウが現れる。

Install Directoryにはc:¥tomcat50-jwsdp を選ぶ。Shared Installationつまりhomeとbaseを違う場所に設定するのにはチェックをつけないのが無難だ。
Display NameはJWDSPとした。
UserNameとPasswordは,tomcat自体ではなく,WSDPをインストールしたときに設定した管理者のユーザ名をパスワードを記入する。
これで「ok」をクリックすると,上のように新しいTomcatが追加される。スタートしてみると,しかしエラーが・・・・あれ?
今やったらエラーが出なかった。
いや,このままでスタートするとShared Memoryがなんとかゆーて立ち上がらないときがあるんですけど。どうやらそれはデバッグのメモリかなんかに関わっているらしいんですけど。そのときはこのJWSDP Tomcatのノードを右クリックしてプロパティを出してデバガの設定部分を
「Debugging Type」を「Shared memory」から「Socket」にすると,デバッグモードでの起動はできなくなるがとにかく立ち上がる,と書こうと思ったんだけど今やったら必要なくフツーに立ち上がった。
なぜ?
まいっか。とにかく,立ち上がるとすでにいくつかのWebサービスやWebアプリケーションが配備されている。

おおっと失礼。jaxrpc-MyHelloWorldというのがこれから説明しようという自力で作成したWebサービスである。最初から配備されていたのはjaxrpc-HelloWorldのほうだけだヨ。
だがいったいどうやってこのWSDPを使ってWebサービスを作れというのか。それにはまずサンプルソースをいじってみるに限る。
実は,これのやり方は全くわかっていないわけではない。
ソースをどこかのディレクトリに作っておく。
wscompileとかwsdeployというタスクを含むbuild.xmlファイルを書いて実行し,このソースから必要なWebモジュールを作ってサーバにデプロイする。
というもののはずなのだ。どうしてワタシがそれを知っているかというと,
全然未完だけど。こっちのほうはサ〜,チュートリアル親切だったゼSunさんヨ〜。WSDPのチュートリアルあるけど,JAX-RPCについての説明が見当たらないのはなぜなぜなぜなの?
とにかく,サンプルソースだが・・・これは結局「Favorite」ウィンドウを使うというのが一番よいことがわかった。
これ,もしかすると「ファイルマウントができねエエエエエ」という多くのユーザの叫びに答えたものなのかな,などといまどきになって思い始めてきた。
やり方はカンタン,「Favorites」ウィンドウに切り替える。デフォルトでは出ていないかも知れないので,メニューバーから「Window」->「Favorites」を選択すれば出る。
この「Favorites」ノードをクリックして「Add to Favorite」を選択する。そしてファイルチューザから
C:¥Sun¥jwsdp-1.5¥jaxrpc
を選べばよい。すると昔懐かしいマウント画面のようなものが見られる。

ソースファイルは「samples」->「HelloWorld」->「src」フォルダの中にある。

サービス側のソースが「HelloImpl.java」である。あれ,インターフェイスは?というところだが,このサンプルでは別のところにあるらしい。
よくわかんないけどッ。
クライアント側のソースが「HelloClient.java」だ。
クライアントファイルを見てみよう。HelloClient.javaノードをダブルクリックすると,ソースエディタにソースコードが現れる。

エラーを示す赤線がたくさん出ているが,これは気にしない。なぜなら,今回はNB標準のコンパイルシステムは使わないからだ。WSDPに用意されているbuild.xmlファイルがいろいろなクラスパスを全て用意してコンパイルしてくれる。
さて,最初の最初,このサンプルクライアントを実行してみる。JWSDPと名前をつけたほうのTomcatが起動してあることを確認して,「Favorites」ウィンドウ上で「HelloClient」ノード・・・には手をつけない。つけても毒にも薬にもならずエラーが出るはずだ。
手をつけるのは「build.xml」ノードのほうである。
これのターゲットである「run-client」ノードを右クリックして「Run Target」とやればよい。

するとコンソール上で蟻が走る走る。最後に

おお。出たらしい。クライアントで送信した「JAXRPC Sample」という文字列にサービスでのしつけて返してきた,というわけだ。
このように,WSDPのサンプルサービスの起動とクライアントの実行は,NetBeans4に全く関係ないにも関わらず,NetBeansがグラフィカルに操作する場所を与えてくれるのだ。
次にやることと言えば,コイツらを編集しちゃうことでしょう。
まずカンタンそうなのがクライアントのほうだ。今表示させたソースを編集する。先述したように赤線は気にしない。NetBeansはなァ!そんなしみったれた了見で使うもんぢゃァねェんだヨ!
![]()
と,送信文字列の内容を書き換える。そうして,さきほど同様,このHelloClient.javaノードをクリックしたい気持ちを押さえ「build.xml」ノードの「run client」ターゲットノードを右クリック実行だ。

このように,クライアントファイルの編集と実行は,カンタンにできる。カンタンでしょ?
さて,問題はサービスのほうだ。実は今起動しているサービスはワタシが配備したものではなく,WSDPのインストール時に自動で配備されたものらしい。そしてこれをカンタンに上書きすることはできなかった。まず,今動いているjaxrpc-HelloWorldサンプルを止めて,削除する必要がある。これはNetBeans上で行える。

このように,Webアプリケーションのノードを右クリックして「Stop」及び「Undeploy」を選べばよい。
さて,サービスを編集して再配備してみよう。まず,「HelloImpl.java」ノードをダブルクリックして編集画面にそのソースを出す。そしてここを編集する。

ソースを編集したら,次は設定ファイルだ。
「build.properties」をまず編集する。編集箇所は,最後のほうにあるこの場所だ。

これはWebコンテナをどこにするかという設定だ。containerの値が,sjswsつまりSun Java Studio Web Serverになっているようだ。
バグですかこれは?まあいい。このように修正する。
まずcontainerをtomcatにした。
それからtomcat.rootのファイルパスを変更した。
これでbuild.propertiesを保存する。次はtomcat.xmlだ。開いてみると
![]()
というふうに,要するにTomcatのwebappsフォルダに作成したWebモジュールをコピーせよ,というきわめて実際的な操作の指定が・・・なんだかファイルがあるから必要ない,と書いてある。だがやってみたら必要だった。
バグですかッ!?
そこでこの部分をコメントアウトアウトする。
保存したら,「build.xml」で,今度は「deploy-war」ターゲットの実行だ。
また蟻がわんさか走って,ビルドが成功したようなら,Tomcatを一度終了してまた起動する。
そして,「run-client」ターゲットをまた,実行する。

今度は,サービスもカスタマイズできたようだ。よかったよかった。
しかしサンプルをいじってばかりじゃ面白くない。やはりゼロからマイJAX-RPCサービスを作りたいものだ。
このWSDPのサンプルをそっくりそのまま,というわけではないが必要と思われるものを,いつもNetBeans4で作業をしているフォルダの中にコピーして,NetBeans4から操作して,WSDPTomcatに配備してみることにした。このプロジェクトのルートフォルダ名を,wsdptwoとする。

ただし,サービスクラスのインターフェイスだけは作ってみた。MyHello.IFである。
さて,話はカンタン。サンプルで「Hello」とあるのをことごとく「MyHello」に書き換える。エンドポイントの設定やパッケージや全てだ。そしてbuild.xmlのターゲット「deploy-war」を実行する。
最初に出たエラーは,「MyHelloService.wsdlが見つかりません」だった。
そりゃないヨ。あんたが作ってくれるんじゃないの!?
よく調べてみると,「このbuild.xmlファイルで参照しているconfig.xmlで要求しているMyHelloService.wsdlが見つかりません」というエラーメッセージだった。
そこでconfig.xmlを調べてみる。
<configuration
xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
<wsdl
location="./etc/MyHelloWorldService.wsdl"
packageName="myhello" />
</configuration>
ええそうです自分で書いたっていうかHelloWorldサンプルの該当ファイルのHelloの部分をMyHelloにしてパケジ名も書き換えました。でもこれってこう書けば作ってくれるもんだと思ってたんだけドォーッ。
果たして,もとのサンプルにはwsdlファイルがある。

これって,自動生成されたものだと思ってたんだけどぉーッ。
これまではdeploy-warターゲットの中味を全然見ることなく動かしていた。ていうか見ろヨ!build.xmlを調べてみる。すると
deploy-war>build-war>create-war>compile-server>generate-server>prepare
というイモヅル式依存関係であることがわかった。
まずターゲットprepareだ。これは,ファイルの出力先などに使うディレクトリを作成する作業で,特に記すこともないだろう。
次がgerenate-server。その主な部分はこれだ。
<wscompile
keep="true"
import="true"
base="${samplesbuild}/${appname}/classes/server"
xPrintStackTrace="true"
verbose="false"
model="${samplesbuild}/${appname}/${model.rpcenc.file}"
classpath="${compile.classpath}"
config="${config.rpcenc.file}">
</wscompile>
wscompileというタスクは,WSDPについているJAX-RPCのドキュメント
file:///C:/Sun/jwsdp-1.5/jaxrpc/docs/jaxrpc-tools.html
の「wscompile」ツールに該当する。こちらと引数を照らし合わせながら研究してみる。
まず,keep="true"というのは,生成する一時ファイルをそのままにしておくということ。
import="true"がクセモノだ。これは,「WSDLファイルを読んで必要なクラスのテンプレートを作成する,ということのようだ。
model=....というのは,この生成過程をモデルファイルにして書き出してあとで再利用などする,ということのようだ。
config=...の中味は,プロパティ値になっているが,つまりはconfig.xmlを指定しているのだ。
つまり,generate-serverというターゲットは
config.xmlで指定してあるWSDLファイルを読んで必要なクラスのテンプレートを作成する
という処理をやっているのだ。
ちなみに,クラスの出力先は
"${samplesbuild}/${appname}/classes/server"
すなわち, サンプルの場合
C:¥Sun¥jwsdp-1.5¥jaxrpc¥build¥samples¥HelloWorld¥classes¥server
ということになる。
そのあとがcompile-serverだ。この主な部分は
<javac srcdir="${samples.home}/${appname}/src/server"
destdir="${samplesbuild}/${appname}/classes/server"/>
と考えればよいだろう。${samples.home}というのは,ここでは上の${samplesbuild}....とは違う。
${samples.home},これはHelloIFとかHelloImplを作成した場所で,サンプルの場合
C:¥Sun¥jwsdp-1.5¥jaxrpc¥samples¥HelloWorld
のことである。
つまり
さっきWSDLファイルにもとづいて自動作成したクラス群に,実体として自前で作成したソースをコンパイルして作ったクラスを加える
という処理らしい!
で,create-war はそれらのクラスや,WSDLファイル,web.xml, jaxrpc-riなどのWeb関係のファイルをまとめてwarにする。このファイルはまだ,デプロイできない原材料warである。
さらに,このcreate-warで作った生warファイルを加工して,デプロイできる状態にするのがbuild-war。ここでwsdeployというタスクを行う。
<wsdeploy
inWarFile="${samplesbuild}/${appname}/jaxrpc-${appname}-raw.war"
outWarFile="${samplesbuild}/${appname}/jaxrpc-${appname}.war"
>
</wsdeploy>
というのがwsdeployの主要な部分だ。要は,必要な設定ファイルを取り揃えてたばねた生warファイルと,wsdeployで処理したデプロイ用の完成品につける名前を指定するだけだ。
deploy-warはこの完成品を実際にTomcatのwebappsフォルダにコピーするだけのこと。
つまり,このdeploy-warの流れは
それはまずい。だってWSDLファイルなんて書き方わかんないもん。
やはり,JavaクラスからWSDLファイルを作成するボトムアップ方式がやりたいものだ。
ドキュメントを見る。ていうか最初から見ろ。それによると,wscompileでサービスクラスを作るには三つの方式があるらしい。
どの方法で行うかは,config.xmlで詳細を指定する。
するとこの場合wscompileでは,import="true"というオプションをはずす。また,サーバーサイドなのでserver="true"というオプションを加える。
<wscompile
keep="true"
server="true"
・・・・
また,config.xmlの内容もこのように書き換える。
<service name="MyHelloService"
targetNamespace="http://myhello.noniko.com/wsdl"
typeNamespace="http://myhello.noniko.com/types"
packageName="myhello">
<interface name="myhello.MyHelloIF"
servantName="myhello.MyHelloImpl"/>
</service>
<wsdl>タグをやめて,<interface>タグの指定に置き換えるのだ。
さてこれでランザターゲット・デプロイ・ウォー!
はぁ=?
調べてみる。どうやらwscompileで参照するconfig.xmlで指定してあるmyhello.MyHelloIFが見つかりません,ということになっている。
クラスパスか?いや,そんなことはない。だってwscompileのベースディレクトリは
サンプルではbase="${samplesbuild}/${appname}/classes/server",つまりクラスファイルが出力されているはずの場所になっている。なんで自分のベースディレクトリにあるものが見つからないのか,あるいはそもそもクラスファイルがないとか?
我が作業場所のそこ(具体的にはwsdptwo/build/classes/serverフォルダ)を開けてみる。
ない。
なきゃ読めねーよッ!なんでないんだ?
そりゃねーだろう。
だってターゲットの依存関係はgenerate-serverをやってからcompile-serverをやることになっているのだ。HelloIF.javaなどをコンパイルするのはcompile-serverだ。で,これまでターゲットを何度か走らせているがみんなgenerate-serverを未遂で止まっている。compile-serverまで一度も到達していないのだ。じゃあできてるわけないじゃん。
ていうかcompile-serverをやる前にgenerate-serverをやるてのは変じゃん。
これはもしかするとターゲットの依存関係そのものを変えなければならないのではないだろうか。変えてみた。
まず,自前のMyHelloIFやMyHelloImplをコンパイルする。
<target name="compile-server" depends="prepare">
<javac srcdir="${proj.home}/src/server"
destdir="${samplesbuild}/classes/server"
......
ここで${proj.home}はbuild.propertiesファイルで別途指定した,我がプロジェクトの場所である。
それから,config.xmlで指定したクラスからWSDLファイル,及びいろいろなテンプレートを作ってもらう。
<target name="generate-server" depends="compile-server">
......
<wscompile
keep="true"
server="true"
........
で,デプロイ・ウォー。よしよし,これでできたぞ!
大局的にわー。これでできたんだけどー。実は途中なんどかクラスパスで道に迷った。
まず,サンプルのbuild.propertiesでは,このファイルのある場所を基点としたパスの設定をしている。
buildhome=../../build
build.dir=${buildhome}
jwsdphome=${buildhome}/../..
これはよろしくない。我がプロジェクトは全然別の場所にあるからだ。こちらのbuild.propertiesでは,絶対パスを使った。
jwsdphome=/Sun/jwsdp-1.5
さらに
nbworks.home=/nonidata/nb4rcworks
proj.home=${nbworks.home}/wsdptwo
buildhome=${proj.home}/build
build.dir=${buildhome}
samplesbuild=${buildhome}
みたいに,自分流にカスタマイズしておく。
また,build.xmlでは,必要なクラスパスを全部このファイル中で指定してくれている。
<path id="compile.classpath">
<pathelement location="${javamail.jar}"/>
<pathelement location="${jaf.jar}"/>
<pathelement location="${jaxp-api.jar}"/>
.....
</path>
と,WSDPのライブラリファイルを全て指定しておいて,いろいろなところで
<classpath refid="compile.classpath"/>
とこの一連のクラスパス指定を参照するようになっている。
この一連のクラスパス指定に
<pathelement path="${samplesbuild}/classes/server"/>
を付け加えることも必要であった。ターゲットの順序が変わったから,であろう。
実は,その前にNetBeans.ORGのドキュメントで,NB4でJAX-RPC,というのを読んでいる。
http://www.netbeans.org/kb/articles/tutorial-webservice-40.html
これは,NetBeans4でWebアプリケーションプロジェクトを作って,そこにJAX-RPCに必要なファイルを作成する。
だが,それらは,
Hello_IF
Hello_Impl
のような,自前のJavaファイル,
そしてjaxrpc-ri.xml
だけだ。
ビルドスクリプトは,NetBeansのbuild.xmlファイルに,要するにwsdeployの部分を書き加えるだけだ。wscompileなどチッタコッチャないという感じ。
第一,いろいろやる間どうもわたしが疑問に思っていたのは,config.xmlとjaxrpc-ri.xmlではかなり同じようなことを書かなければならなかった,ということだ。二度手間感が強い。
この違いは一体なんなのだ?
なんなのだってドキュメント見りゃわかった。
「wsdeployは実はwscompileをserverモードで走らせています。このwscompileによりWSDLや必要なクラスファイルが作成されるのです」
「JWSDPではwsdeployを行うことが必要ですが,deploytoolとかasadminを使えば,その必要はありません」
つまりdeploytoolとか使うんだったら,wscompileさえすればいいってことか・・・・
いったい,このサンプルは,どんな人がどんなことをする想定で,作られているんだろう・・・・
・・・・
ま,いっか。おかげで,wscompileとwsdeployについては,結構よくわかった。
では上記のNBドキュメントの通りにやってみよう。ただし,ドキュメントではNBの内蔵Tomcatに配備している。こちらはじゃあちょっとだけ違う条件で情報発信,ということでこのままJWSDPのTomcatを使い続けることにした。
くわしいことはURLを再掲するのでNBドキュメントを見てね
Web Applicationのプロジェクトを作って,名前をwsdpthreeにする。
まず,nbprojectにwebservice.propertiesというファイルを作って,以下のプロパティを指定する。
nbworks.home=/nonidata/nb4rcworks
proj.name=wsdpthree
proj.home=${nbworks.home}/${proj.name}
proj.web=${proj.home}/web
proj.src=${proj.home}/src
proj.build=${proj.home}/build
proj.build.web=${proj.build}/web
tomcat.root=/tomcat50-jwsdp
catalina.home=${tomcat.root}
jwsdphome=/Sun/jwsdp-1.5
jwsdpshared=${jwsdphome}/jwsdp-shared
jaxrpchome=${jwsdphome}/jaxrpc
saajhome=${jwsdphome}/saaj
javamail.jar=${jwsdpshared}/lib/mail.jar
jaf.jar=${jwsdpshared}/lib/activation.jar
jaxrpc-api.jar=${jaxrpchome}/lib/jaxrpc-api.jar
jaxrpc-impl.jar=${jaxrpchome}/lib/jaxrpc-impl.jar
jaxrpc-spi.jar=${jaxrpchome}/lib/jaxrpc-spi.jar
saaj-api.jar=${saajhome}/lib/saaj-api.jar
saaj-impl.jar=${saajhome}/lib/saaj-impl.jar
jax-qname.jar=${jwsdpshared}/lib/jax-qname.jar
ant.jar=${jwsdphome}/apache-ant/lib/ant.jar
ああ,もうひとつ。NetBeansでWebアプリケーションプロジェクトをビルドしたときにはプロジェクト名.warというwarファイルができる。しかし,これを変更しておきたい。wsdeployを行って最終的にできるファイルをプロジェクト名.warにしたいのだ。
そこで,project.propertiesの,最後の方にあるwar.nameプロパティの値を変更する。
war.name=wsdpthree-nb.war
で,build.xmlに以下の表記をする。
<property file="nbproject/webservice.properties"/>
で,上記プロパティファイルを読み込む。
次はクラスパスのうち,Webサービスに必要なところだけ持ってくる。
<path id="compile.classpath">
<pathelement location="${javamail.jar}"/>
<pathelement location="${jaf.jar}"/>
<pathelement location="${jaxrpc-api.jar}"/>
<pathelement location="${jaxrpc-spi.jar}"/>
<pathelement location="${jaxrpc-impl.jar}"/>
<pathelement location="${saaj-api.jar}"/>
<pathelement location="${saaj-impl.jar}"/>
<pathelement location="${jax-qname.jar}"/>
<!--pathelement location="${ant.jar}"/-->
</path>
一時ファイルを置く場所を作ろう。
<target name="init-create-server" description="craete
folders for tasks">
<mkdir dir="build/temp"/>
</target>
以後,クラスパスの設定をここかしこでする。これで,「Option」->「Build」->「Ant Setting」をいじる必要がなくなるんだヨ!
<target name="create-server" description="Create Service-Side
Artefacts" depends="init-create-server">
<taskdef name="wsdeploy" classname="com.sun.xml.rpc.tools.ant.Wsdeploy">
<classpath refid="compile.classpath"/>
</taskdef>
<wsdeploy
outWarFile="dist/${proj.name}.war"
inWarFile="dist/${proj.name}-nb.war"
keep="true"
verbose="true"
tmpdir="build/temp">
<classpath refid="compile.classpath"/>
</wsdeploy>
</target>
で,JWSP-Tomcatへのデプロイつかコピーをするターゲット。
<target name="deploy-war" description="Deploy war to
JWSDP tomcat" depends="create-server">
<copy file="${proj.home}/dist/${proj.name}.war" todir="${tomcat.root}/webapps"/>
</target>
ちなみに,jaxrpc-ri.xmlの主要なトコ。
<webServices
.........
urlPatternBase="/wsdpthree">
...........
<endpointMapping
endpointName="YourHello"
urlPattern="/yourhello"/>
</webServices>
これでdeploy-warをくれてやれば,あとはJWSDP-Tomcatを再起動して,
http://localhost:8080/wsdpthree/yourhello
にアクセスすることで,Webサービスの情報にアクセスできるゾ!