Metro JAX-WS
JAX-WSを利用して、WSDLファイルからソースを自動生成する方法についてですが、
通常、業務系のサービスの場合、WSDLを先に記述することが多いような気がするので、トップダウンで、サービスを開発することが前提になります。
サンプル用のWSDLを準備します。
今回は、サンプルなので、すべての定義をWSDLで行うことにします。
本当は、XML Schemaを定義した方がいいと思います。
リクエストとレスポンスの定義をtypesに下記の様に定義します。
<types> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://developer.co.jp/system/dev/schemas/service/message_1/getMessage" elementFormDefault="qualified"> <!-- リクエスト用のスキーマ定義です。 --> <element name="messageRequest"> <complexType> <sequence> <element name="messageId"> <simpleType> <restriction base="int"> <totalDigits value="5"/> </restriction> </simpleType> </element> <element name="actionDt" type="dateTime"/> </sequence> </complexType> </element> <!-- レスポンス用のスキーマ定義です。 --> <element name="messageResponse"> <complexType> <sequence> <element name="message"> <simpleType> <restriction base="string"> <minLength value="1"/> <maxLength value="1000"/> </restriction> </simpleType> </element> </sequence> </complexType> </element> </schema> </types>
名前空間をdefinitionsに書いておきます。
<definitions name="MessageService_1_0" targetNamespace="http://developer.co.jp/system/dev/wsdl/MessageService_1_0" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://developer.co.jp/system/dev/wsdl/MessageService_1_0" xmlns:getMsg="http://developer.co.jp/system/dev/schemas/service/message_1/getMessage">
上記の定義を利用して、メッセージ、ポートタイプ、バインディングを定義します。
<message name="messageRequest"> <part name="messageRequest" element="getMsg:messageRequest"/> </message> <message name="messageResponse"> <part name="messageResponse" element="getMsg:messageResponse"/> </message> <portType name="MessageService"> <operation name="getMessage"> <input name="messageRequest" message="tns:messageRequest"/> <output name="messageResponse" message="tns:messageResponse"/> </operation> </portType> <binding name="MessageService" type="tns:MessageService"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="getMessage"> <soap:operation soapAction="http://developer.co.jp/system/dev/schemas/service/message_1/getMessage"/> <input name="messageRequest"> <soap:body use="literal"/> </input> <output name="messageResponse"> <soap:body use="literal"/> </output> </operation> </binding>
最後に、サービスを定義します。
<service name="MessageService"> <port name="MessageService" binding="tns:MessageService"> <soap:address location="REPLACE_WITH_ACTUAL_URL"/> </port> </service>
最終的に定義されたWSDLは、下記になります。
<?xml version="1.0" encoding="UTF-8" ?> <definitions name="MessageService_1_0" targetNamespace="http://developer.co.jp/system/dev/wsdl/MessageService_1_0" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://developer.co.jp/system/dev/wsdl/MessageService_1_0" xmlns:getMsg="http://developer.co.jp/system/dev/schemas/service/message_1/getMessage"> <types> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://developer.co.jp/system/dev/schemas/service/message_1/getMessage" elementFormDefault="qualified"> <!-- リクエスト用のスキーマ定義です。 --> <element name="messageRequest"> <complexType> <sequence> <element name="messageId"> <simpleType> <restriction base="int"> <totalDigits value="5"/> </restriction> </simpleType> </element> <element name="actionDt" type="dateTime"/> </sequence> </complexType> </element> <!-- レスポンス用のスキーマ定義です。 --> <element name="messageResponse"> <complexType> <sequence> <element name="message"> <simpleType> <restriction base="string"> <minLength value="1"/> <maxLength value="1000"/> </restriction> </simpleType> </element> </sequence> </complexType> </element> </schema> </types> <message name="messageRequest"> <part name="messageRequest" element="getMsg:messageRequest"/> </message> <message name="messageResponse"> <part name="messageResponse" element="getMsg:messageResponse"/> </message> <portType name="MessageService"> <operation name="getMessage"> <input name="messageRequest" message="tns:messageRequest"/> <output name="messageResponse" message="tns:messageResponse"/> </operation> </portType> <binding name="MessageService" type="tns:MessageService"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="getMessage"> <soap:operation soapAction="http://developer.co.jp/system/dev/schemas/service/message_1/getMessage"/> <input name="messageRequest"> <soap:body use="literal"/> </input> <output name="messageResponse"> <soap:body use="literal"/> </output> </operation> </binding> <service name="MessageService"> <port name="MessageService" binding="tns:MessageService"> <soap:address location="REPLACE_WITH_ACTUAL_URL"/> </port> </service> </definitions>
次に、JAX-WSの実装を下記のサイトからダウンロードしてきます。
https://jax-ws.dev.java.net/2.1.7/
今回は、 Eclipseで開発します。
EclipseでDynamic Web projectを作成してください。
ディレクトリ構成ですが、下記の様な構成とします。
① ソース格納用 ⇒ src
② 自動生成ソース格納用 ⇒ gen
③ JAX-WSライブラリー格納用 ⇒ WebContent/WEB-INF/lib
④ WSDL格納用 ⇒ WebContent/WEB-INF/wsdl
⑤ ANTファイル ⇒
ダウンロードしたライブラリーを WebContent/WEB-INF/lib/の下にコピーしておきます。
作成したWSDLファイルは、WebContent/WEB-INF /wsdl/の下にコピーします。
次にbuild.xml(ANTです。)をプロジェクト直下に作成します。
作成したANTは、下記のような内容です。
<?xml version="1.0" encoding="UTF-8"?> <project name="MessageService"> <property name="build.lib" value="WebContent/WEB-INF/lib/"/> <property name="build.src" value="src"/> <property name="build.gen" value="gen"/> <property name="build.bin" value="bin"/> <property name="wsdl.dir" value="WebContent/WEB-INF/wsdl/MessageService_1_0.wsdl"/> <!-- CLASSPATHにJAX-WSのライブラリーパスを通しておく。 --> <path id="classpath"> <fileset dir="${build.lib}"> <include name="*.jar"/> </fileset> </path> <!-- wsimportタスクの定義 --> <taskdef name="wsimport" classname="com.sun.tools.ws.ant.WsImport"> <classpath refid="classpath"/> </taskdef> <target name="wsimport"> <wsimport wsdl="${wsdl.dir}" destdir="${build.bin}" sourcedestdir="${build.gen}" keep="true" verbose="true"/> </target> </project>
これで準備完了です。
後は、ANTタスクのwsimportを実行すれば、
genディレクトリに自動生成されたソースが作成されるはずです。
JAX-WSは、JAXBでのデータのバインディングがされます。
自動生成されたソースの中で、サービスの実装クラスがimplementsするインターフェイスが生成されています。
そのインターフェイスのパッケージは、WSDLのデフォルト名前空間がパッケージとしてマッピングされたパッケージ配下にあります。
今回は、jp.co.developer.system.dev.wsdl.messageservice_1_0のパッケージ配下にあるMessageServiceがそのインターフェイスになります。
下記がそのインターフェイスになります。
package jp.co.developer.system.dev.wsdl.messageservice_1_0; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.xml.bind.annotation.XmlSeeAlso; import jp.co.developer.system.dev.schemas.service.message_1.getmessage.MessageRequest; import jp.co.developer.system.dev.schemas.service.message_1.getmessage.MessageResponse; import jp.co.developer.system.dev.schemas.service.message_1.getmessage.ObjectFactory; /** * This class was generated by the JAX-WS RI. * JAX-WS RI 2.1.7-b01- * Generated source version: 2.1 * */ @WebService(name = "MessageService", targetNamespace = "http://developer.co.jp/system/dev/wsdl/MessageService_1_0") @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE) @XmlSeeAlso({ ObjectFactory.class }) public interface MessageService { /** * * @param messageRequest * @return * returns jp.co.developer.system.dev.schemas.service.message_1.getmessage.MessageResponse */ @WebMethod(action = "http://developer.co.jp/system/dev/schemas/service/message_1/getMessage") @WebResult(name = "messageResponse", targetNamespace = "http://developer.co.jp/system/dev/schemas/service/message_1/getMessage", partName = "messageResponse") public MessageResponse getMessage( @WebParam(name = "messageRequest", targetNamespace = "http://developer.co.jp/system/dev/schemas/service/message_1/getMessage", partName = "messageRequest") MessageRequest messageRequest); }
上記のインターフェイスを見ると、getMessageのメソットが定義されています。
オペレーション名がそのままメソット名になっています。
また、リクエスト及び、レスポンスは、スキーマ定義した内容がマッピングされたクラスが使われます。
このインターフェイスを実装していきます。
package jp.co.developer.system.dev.wsdl.messageservice_1_0.logic.impl; import javax.jws.WebMethod; import javax.jws.WebResult; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.xml.bind.annotation.XmlSeeAlso; import jp.co.developer.system.dev.schemas.service.message_1.getmessage.MessageRequest; import jp.co.developer.system.dev.schemas.service.message_1.getmessage.MessageResponse; import jp.co.developer.system.dev.schemas.service.message_1.getmessage.ObjectFactory; import jp.co.developer.system.dev.wsdl.messageservice_1_0.MessageService; @WebService(name = "MessageService", targetNamespace = "http://developer.co.jp/system/dev/wsdl/MessageService_1_0") @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE) @XmlSeeAlso({ ObjectFactory.class }) public class MessageServiceImpl implements MessageService { @WebMethod(action = "http://developer.co.jp/system/dev/schemas/service/message_1/getMessage") @WebResult(name = "messageResponse", targetNamespace = "http://developer.co.jp/system/dev/schemas/service/message_1/getMessage", partName = "messageResponse") public MessageResponse getMessage(MessageRequest messageRequest) { MessageResponse response = new MessageResponse(); if (messageRequest.getMessageId() == 1) { response.setMessage("テストメッセージ1です。"); } else { response.setMessage("テストメッセージ2です。"); } return response; } }
これで実装は、完了です。
なぜか?インターフェイスに定義されているアノテーションが実装クラスに引き継がれないみたいな?
GlassFishにデプロイしてみましたが、サービスとして認識されないようです。
今回は、実装クラスにも同様のアノテーションを追加しています。
これで、サービスとして認識されました。
デプロイには、web.xmlとsun-jaxws.xmlの2つの定義が必要になります。
まず、web.xmlですが、リスナーを定義します。
利用するリスナーは、下記のリスナーです。
<listener> <listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class> </listener>
次にサーブレットの設定をします。
<servlet> <servlet-name>MessageService_1_0</servlet-name> <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>MessageService_1_0</servlet-name> <url-pattern>/MessageService</url-pattern> </servlet-mapping>
定義したweb.xmlは、下記になります。
<?xml version="1.0" encoding="UTF-8"?> <web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>MessageService</display-name> <listener> <listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class> </listener> <servlet> <servlet-name>MessageService_1_0</servlet-name> <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>MessageService_1_0</servlet-name> <url-pattern>/MessageService</url-pattern> </servlet-mapping> <session-config> <session-timeout>60</session-timeout> </session-config> </web-app>
sun-jaxws.xmlには、エンドポイントやインターフェイス及び実装クラスなでの定義を記述します。
記述内容は、下記の様になります。
<?xml version="1.0" encoding="UTF-8"?> <endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0"> <endpoint name="MessageService" interface="jp.co.developer.system.dev.wsdl.messageservice_1_0.MessageService" implementation="jp.co.developer.system.dev.wsdl.messageservice_1_0.logic.impl.MessageServiceImpl" wsdl="WEB-INF/wsdl/MessageService_1_0.wsdl" service="{http://developer.co.jp/system/dev/wsdl/MessageService_1_0}MessageService" port="{http://developer.co.jp/system/dev/wsdl/MessageService_1_0}MessageService" url-pattern="/MessageService" /> </endpoints>
WARファイルを作成するタスクをANTファイルに追加します。
WARファイルを作成する下記のタスクを追加定義します。
<target name="war"> <mkdir dir="${build.dist}"/> <mkdir dir="${tmp.WebContent}"/> <mkdir dir="${tmp.src}"/> <mkdir dir="${tmp.classes}"/> <mkdir dir="${tmp.lib}"/> <mkdir dir="${tmp.wsdl}"/> <copy todir="${tmp.src}"> <fileset dir="${build.src}"/> <fileset dir="${build.gen}"/> </copy> <copy todir="${tmp.lib}"> <fileset dir="${build.lib}"/> </copy> <copy todir="${tmp.wsdl}"> <fileset dir="${build.wsdl}"/> </copy> <copy file="WebContent/WEB-INF/web.xml" tofile="tmp/WebContent/WEB-INF/web.xml"/> <copy file="WebContent/WEB-INF/sun-jaxws.xml" tofile="tmp/WebContent/WEB-INF/sun-jaxws.xml"/> <javac srcdir="${tmp.src}" destdir="${tmp.classes}" source="1.6" encoding="UTF-8"> <classpath> <path refid="classpath"/> </classpath> </javac> <jar destfile="${tmp.lib}/${project.name}_${version}_${revision}.jar" basedir="${tmp.classes}"/> <war destfile="${build.dist}/${project.name}_${version}_${revision}.war" basedir="tmp/WebContent" webxml="tmp/WebContent/WEB-INF/web.xml"> <webinf dir="tmp/WebContent/WEB-INF/" includes="sun-jaxws.xml"/> </war> </target>
これで、WARを作成して、GlassFishにデプロイします。
デプロイ後、http://localhost:8080/MessageService_1_0/MessageService?WSDLへアクセスして、WSDLが表示されれば成功です。