早速サンプル・プログラムのWSDLを作成してみましょう。WSDLはXMLで記述するために、Webサービス・プロバイダがWSDLの仕様書を見ながらエディタなどで書くことも可能です。しかし、これでは「オートマ運転」とはいえません。WSDLさえも自動で作りたいと思いませんか? 実はAxisを利用すると、WSDLをプログラムで自動生成することができます。
AxisにはJava2WSDLというユーティリティが付属しています。このユーティリティでWSDLファイルを自動生成します。Webサービス・プロバイダはすでにJavaBeansと配置記述ファイルを作成していますので、これらを基にして、WSDLファイルを作り出します。
このユーティリティを実行するには、<@WORK>ディレクトリに移って、第1回以降使っている環境変数設定バッチファイルを起動します。環境変数設定後、<@WORK>ディレクトリで下記のコマンドを実行します。
●Java2WSDLコマンド(1行に記述して実行)
>java org.apache.axis.wsdl.Java2WSDL -o SimpleAddService.wsdl
-l http://localhost:8080/axis/servlet/AxisServlet
-n SimpleAddService atmarkit.SimpleAddBean
|
実行後、<@WORK>ディレクトリに「SimpleAddService.wsdl」ファイルができていればOKです。このWSDLファイルの中をのぞいてみる前に、このコマンドを少しだけ解説しておきましょう。
Java2WSDLコマンドには多くのオプションがありますが、ここでは必要最低限のオプションだけを利用しています。詳しくはAxisのマニュアルを参照してください。
>java org.apache.axis.wsdl.Java2WSDL
-o SimpleAddService.wsdl
(1) 出力ファイル名
-l http://localhost:8080/axis/servlet/AxisServlet
(2) WebサービスのURL
-n SimpleAddService
(3) サービス名
atmarkit.SimpleAddBean
(4) 公開するJavaBeans
|
(1)の「-o」オプションには出力するWSDLファイル名を記述します。ここでは、「サービス名+.wsdl」とします。配置記述ファイル(SimpleAddService.wsdd)と似ていますので注意してください。
(2)の「-l」オプションにはWebサービスのURLを記述します。今回の場合、Servlet版のWebサービス・エンジンを利用していますので、そのServletのURLそのものになります。今回のサンプル・プログラムではWebサービスもWebサービス・クライアントも同じPC内でテストしていますので、「localhost」と記述していますが、実際にネットワーク環境に公開する場合は、Webサービスを実行するサーバのドメイン名やIPアドレスを記述することになります。
(3)の「-n」オプションには配置記述ファイルに書き込んだWebサービスの名称を記述します。配置記述ファイル(SimpleAddService.wsdd)には「<service name="SimpleAddService" provider="java:RPC">」と記述しましたので、この「SimpleAddService」を記述します(注:「n」はネームスペースを意味します。本来、XMLがインターネット上で一意に認識できるようにURNを記述しますが、ここでは以降の話を簡略化するためにサービス名をURNとしています。詳しくはAxisのUser's Guideを参照してください)。
最後の(4)には、Webサービスの基になるJavaBeansをパッケージ名付きで指定します。Java2WSDLプログラムはこのJavaBeansの中身を走査して、どのようなメソッドがどのような型で利用できるかを自動的に拾い出します。この自動走査機能はJavaのリフレクションAPIをうまく使った機能といえるでしょう。
WSDLファイルには、Webサービス・リクエスターがWebサービスを理解するための情報が含まれています。XMLで記述されていることから、その内容を理解することは容易です。WSDLファイルの中身を見てみましょう。WSDLファイルは大きく5つの部分に分かれています。それぞれを分けて見てみることにします。
まずは、XMLの大枠構造です。WSDLファイルの本編は<wsdl:definitions> と </wsdl:definitions>の中に入ります。
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="SimpleAddService"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:apachesoap
="http://xml.apache.org/xml-soap"
xmlns:impl="SimpleAddService-impl"
xmlns:intf="SimpleAddService"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
(1)〜(4)の記述
</wsdl:definitions>
|
以下、(1)〜(4)の部分を見てみましょう。
(1)メッセージ定義
ここには、SOAPでやりとりされるメッセージの種類とその型が記述されます。メッセージの種類は、JavaBeansクラスのそれぞれのメソッドを解析して作られていることが分かるでしょう。
<wsdl:message name="getResultValueRequest">
</wsdl:message>
<wsdl:message name="setResultValueResponse">
</wsdl:message>
<wsdl:message name="getInputValueResponse">
<wsdl:part name="return" type="xsd:int"/>
</wsdl:message>
<wsdl:message name="addRequest">
</wsdl:message>
<wsdl:message name="getResultValueResponse">
<wsdl:part name="return" type="xsd:int"/>
</wsdl:message>
以下省略……
|
(2)ポートタイプ定義
ポートタイプには、(1)で定義されたメッセージがどのような機能(operation)として成り立っているかを記述しています。どのメッセージがどの機能の入力(input)と出力(output)になっているかが構造的に記述されています。
<wsdl:portType name="SimpleAddBean">
<wsdl:operation name="add">
<wsdl:input message="intf:addRequest" name="addRequest"/>
<wsdl:output message="intf:addResponse" name="addResponse"/>
</wsdl:operation>
<wsdl:operation name="getInputValue">
<wsdl:input message="intf:getInputValueRequest" name="getInputValueRequest"/>
<wsdl:output message="intf:getInputValueResponse" name="getInputValueResponse"/>
</wsdl:operation>
<wsdl:operation name="setInputValue" parameterOrder="in0">
<wsdl:input message="intf:setInputValueRequest" name="setInputValueRequest"/>
<wsdl:output message="intf:setInputValueResponse" name="setInputValueResponse"/>
</wsdl:operation>
<wsdl:operation name="getResultValue">
<wsdl:input message="intf:getResultValueRequest" name="getResultValueRequest"/>
<wsdl:output message="intf:getResultValueResponse" name="getResultValueResponse"/>
</wsdl:operation>
<wsdl:operation name="setResultValue" parameterOrder="in0">
<wsdl:input message="intf:setResultValueRequest" name="setResultValueRequest"/>
<wsdl:output message="intf:setResultValueResponse" name="setResultValueResponse"/>
</wsdl:operation>
</wsdl:portType>
|
(3)バインディング定義
バインディング情報には、(1)(2)の機能がどのようなプロトコルで利用できるかが記述されています。今回のJavaBeans版Webサービスでは、リモート・プロシージャ型(RPC)のSOAPを利用しています。これは、下線部分に記述されています。
<wsdl:binding name="AxisServletSoapBinding"
type="intf:SimpleAddBean">
<wsdlsoap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="add">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="addRequest">
<wsdlsoap:body encodingStyle
="http://schemas.xmlsoap.org/soap/encoding/"
namespace="SimpleAddService" use="encoded"/>
</wsdl:input>
<wsdl:output name="addResponse">
<wsdlsoap:body encodingStyle
="http://schemas.xmlsoap.org/soap/encoding/"\
namespace="SimpleAddService" use="encoded"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="getInputValue">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="getInputValueRequest">
<wsdlsoap:body encodingStyle
="http://schemas.xmlsoap.org/soap/encoding/"
namespace="SimpleAddService" use="encoded"/>
</wsdl:input>
<wsdl:output name="getInputValueResponse">
<wsdlsoap:body encodingStyle
="http://schemas.xmlsoap.org/soap/encoding/"
namespace="SimpleAddService" use="encoded"/>
</wsdl:output>
</wsdl:operation>
…中略…
</wsdl:binding>
|
(4)サービス定義
どのポートにおいてサービスが提供されているかを記述しています。(3)で定義したバインディング情報を持つWebサービスがどのURLにて利用できるかを定義しています。
<wsdl:service name="SimpleAddBeanService">
<wsdl:port binding="intf:AxisServletSoapBinding"
name="AxisServlet">
<wsdlsoap:address location
= "http://localhost:8080/axis/servlet/AxisServlet"/>
</wsdl:port>
</wsdl:service>
|
WSDLの全体構造はそれほど難しくないことが理解できるでしょう。それでは、(1)〜(4)がどのような関係になっているかを確認してみましょう。