kagamihogeの日記

kagamihogeの日記です。

WildFly 8でWeb Serviceさわる

SOAPとかWSDLとかの方のWeb Serviceをさわる。WildFly使うのは趣味。なんとなく新しいバージョン使った方がいいかな〜とかそういう雰囲気。目標は、サンプルのWeb Serviceをサーバ側で起動して、クライアント側からアクセスできるまで。

準備

EclipseのServerビューからWildFlyを起動できるようにする。

JBoss AS 7.1 + EJB 3.1 + Arquillian動かすところまで - kagamihogeのblogとかを参照してJBoss Toolsいれる。
Serverの設定を↓みたいな感じにして作る。



まだプロジェクト作ってないんでココは空でOK

サンプルWeb Serviceを動かすところまで

Java EE Projectの作成

めんどいのでJBoss Toolsの雛形作成機能を使う。
Help -> JBoss Cenetralを開き、Java EE Web Projectを選択する。

Create a blank projectにチェックを入れる。今回はEJBとかJSFとかゴチャゴチャ入られても邪魔なだけなので。
Target RuntimeはWildFly 8を選択しておく。

この後はテキトーにクリックしていくだけ。プロジェクト名は、jboss8-wsにしておく。


これでプロジェクト作成完了。

サンプルWeb Serviceの作成

ここからWeb Service本体の作成に入っていく。
プロジェクト右クリック -> New -> Other -> Web Services -> Create a Sample Web Serviceを選択する。

次の画面でエラーが出る。プロジェクトはDynamic Web Projectじゃないとダメなのと、web.xmlがしかるべき場所に存在しない、と言っている。

よって、jboss8-ws\src\main\webapp\WEB-INF\web.xmlをつくる。適当なDynamic Web Projectを一個作って、web.xmlだけコピペしてきた。あと、welcome-fileとかは要らないんで消している。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID" version="3.0">
    <display-name>jboss8-ws</display-name>
</web-app>

エラーが消える。

作成されたサンプルWeb Serviceのコード

Javaのコード。

package org.jboss.samples.webservices;

import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService()
public class HelloWorld {

    @WebMethod()
    public String sayHello(String name) {
        System.out.println("Hello: " + name);
        return "Hello " + name + "!";
    }
}

web.xmlも書き換えられる。↑のクラスとメソッドがサーブレットをエンドポイントにするWeb Serviceとして作られたっぽいことが分かります。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID" version="3.0">
    <display-name>jboss8-ws</display-name>
    <servlet>
        <display-name>HelloWorld</display-name>
        <servlet-name>HelloWorld</servlet-name>
        <servlet-class>org.jboss.samples.webservices.HelloWorld</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloWorld</servlet-name>
        <url-pattern>/HelloWorld</url-pattern>
    </servlet-mapping>
</web-app>
起動

デプロイして起動してみる。サーバーログを見る。さっき作ったWeb Serviceが起動したっぽいようなログが途中らへんに流れてきます。

INFO  [org.jboss.ws.cxf.metadata] (MSC service thread 1-4) JBWS024061: Adding service endpoint metadata: id=HelloWorld
 address=http://localhost:8080/jboss8-ws/HelloWorld
 implementor=org.jboss.samples.webservices.HelloWorld
 serviceName={http://webservices.samples.jboss.org/}HelloWorldService
 portName={http://webservices.samples.jboss.org/}HelloWorldPort
 annotationWsdlLocation=null
 wsdlLocationOverride=null
 mtomEnabled=false

クライアントからは恐らく上記ログ中にもある http://localhost:8080/jboss8-ws/HelloWorld にアクセスするのだろうな、ということがわかる。とりあえずブラウザからアクセス。まぁエラーが返ってくるけど、なんかが動いていることは分かる。

<soap:Envelope><soap:Body><soap:Fault><faultcode>soap:Server</faultcode><faultstring>Fault occurred while processing.</faultstring></soap:Fault></soap:Body></soap:Envelope>

http://localhost:8080/jboss8-ws/HelloWorld?WSDL にブラウザからアクセス。何かが見える。

xmlはこんな感じ。こんな長ったらしいXML作った覚えは無いので、javaeeコンテナ側が勝手にWSDL作ってくれることが伺えます。

<wsdl:definitions name="HelloWorldService"
	targetNamespace="http://webservices.samples.jboss.org/">
	<wsdl:types>
		<xs:schema elementFormDefault="unqualified"
			targetNamespace="http://webservices.samples.jboss.org/" version="1.0">
			<xs:element name="sayHello" type="tns:sayHello" />
			<xs:element name="sayHelloResponse" type="tns:sayHelloResponse" />
			<xs:complexType name="sayHello">
				<xs:sequence>
					<xs:element minOccurs="0" name="arg0" type="xs:string" />
				</xs:sequence>
			</xs:complexType>
			<xs:complexType name="sayHelloResponse">
				<xs:sequence>
					<xs:element minOccurs="0" name="return" type="xs:string" />
				</xs:sequence>
			</xs:complexType>
		</xs:schema>
	</wsdl:types>
	<wsdl:message name="sayHelloResponse">
		<wsdl:part element="tns:sayHelloResponse" name="parameters">
		</wsdl:part>
	</wsdl:message>
	<wsdl:message name="sayHello">
		<wsdl:part element="tns:sayHello" name="parameters">
		</wsdl:part>
	</wsdl:message>
	<wsdl:portType name="HelloWorld">
		<wsdl:operation name="sayHello">
			<wsdl:input message="tns:sayHello" name="sayHello">
			</wsdl:input>
			<wsdl:output message="tns:sayHelloResponse" name="sayHelloResponse">
			</wsdl:output>
		</wsdl:operation>
	</wsdl:portType>
	<wsdl:binding name="HelloWorldServiceSoapBinding" type="tns:HelloWorld">
		<soap:binding style="document"
			transport="http://schemas.xmlsoap.org/soap/http" />
		<wsdl:operation name="sayHello">
			<soap:operation soapAction="" style="document" />
			<wsdl:input name="sayHello">
				<soap:body use="literal" />
			</wsdl:input>
			<wsdl:output name="sayHelloResponse">
				<soap:body use="literal" />
			</wsdl:output>
		</wsdl:operation>
	</wsdl:binding>
	<wsdl:service name="HelloWorldService">
		<wsdl:port binding="tns:HelloWorldServiceSoapBinding" name="HelloWorldPort">
			<soap:address location="http://localhost:8080/jboss8-ws/HelloWorld" />
		</wsdl:port>
	</wsdl:service>
</wsdl:definitions>
サンプルWeb Serviceにアクセスするクライアント

サンプルWeb Serviceが動いたっぽいことは分かった。ので、それにアクセスするクライアントを作る。
まず、フツーのjavaプロジェクトを作る。
つぎに、Web ServiceのクライアントにアクセスするためのクラスをWSDLから自動生成する。
プロジェクト右クリック -> New -> Other -> Web Services -> Web Service Client

Service Destinationに http://localhost:8080/jboss8-ws/HelloWorld?WSDL を入力する。

Define custom mapping for namespace to packageにチェック入れれば適当なpackage作ってくれる(と思う)


Finishすると、なんだかしらんが色々なクラスが自動生成される。きっとこの辺のクラスをテキトーに呼び出せば、アレコレ面倒なXML作った解釈したりしなくてもよいのだろう、と感じる。

てなわけで、自動生成されたクラス使ってWeb Serviceにアクセスするコードを書く。なお、これで動いたってだけで、こーいう書き方が正しいのかどうかは調べてないんで分からない。

package wsclient.sample;

import java.rmi.RemoteException;

import org.jboss.samples.webservices.HelloWorld;
import org.jboss.samples.webservices.HelloWorldProxy;

public class Main {

    public static void main(String[] args) throws RemoteException {
        HelloWorld helloWorldWS = new HelloWorldProxy().getHelloWorld();
        System.out.println(helloWorldWS.sayHello("kagamihoge"));
    }
}
ログの確認

ホントーにサーバまでアクセスしにいってるかどうかとかを確認する。上記で作ったコードを実行してみる。
まず、サーバ側。届いてるっぽい。

INFO  [stdout] (default task-10) Hello: kagamihoge

クライアント側。なんかwarningが出てますがソレを気にしないで末尾を見ると、Web Serviceの呼び出し結果が表示されていることが分かります。

 org.apache.axis.utils.JavaUtils isAttachmentSupported
WARNING: 要求されたクラス(javax.activation.DataHandler と javax.mail.internet.MimeMultipart)が見つかりません。Attachmentサポートが利用できません。 / [en]-(Unable to find required classes (javax.activation.DataHandler and javax.mail.internet.MimeMultipart). Attachment support is disabled.)
Hello kagamihoge!

自前のWeb Serviceを動かすところまで

今度は自作のWeb Serviceを作ってみる。といっても、手順はほとんどサンプル動かすのと変わらないのだけど。

Web Serviceの作成

さっき作ったプロジェクトに下記のようなクラスを作る。

package org.jboss.samples.webservices;

import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService()
public class CalcSum {
    
    @WebMethod()
    public int sum(CalcSumInput input) {
        int sum = 0;
        for (int i:input.getInputs()) {
            sum += i;
        }
        
        System.out.println(input.getName() + ":" + sum);
        return sum;
    }

}

サンプルと違うのは、メソッドの引数に独自のクラスを取るところ。そのクラスは単純にデータ突っ込むためのものなので、実質的にgetter/setterだけ。あと、XmlRootElementアノテーションをつけておく。これをつけとくとXMLJavaのクラスとのバインドを勝手にやってくれる。

import java.util.List;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class CalcSumInput {
	private String name;
	private List<Integer> inputs;
	
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public List<Integer> getInputs() {
		return inputs;
	}
	public void setInputs(List<Integer> inputs) {
		this.inputs = inputs;
	}	
}
Web Serviceにアクセスするクライアント

ココの流れはサンプルのときと変わらない。まずWeb Serviceにアクセスするクラスを自動生成するために、プロジェクト右クリック -> New -> Other -> Web Services -> Web Service Clientをして、Destinationには http://localhost:8080/jboss8-ws/CalcSum?WSDL と入力する。と、自動生成される。

んで、テキトーにクライアントのコードを書く。

package wsclient.sample;

import java.rmi.RemoteException;

import org.jboss.samples.webservices.CalcSum;
import org.jboss.samples.webservices.CalcSumInput;
import org.jboss.samples.webservices.CalcSumProxy;

public class Main {

    public static void main(String[] args) throws RemoteException {
        Integer[] nums = {1,2,3,4,5,6,7,8,9,10,};
        CalcSum calcSum = new CalcSumProxy().getCalcSum();
        CalcSumInput input = new CalcSumInput(nums, "kagamihoge");
        System.out.println(calcSum.sum(input));;
    }
}

55と返ってきたんでおっけー。

EJB Webサービスとして動かす

Statelessアノテーション付けるだけだけど。

package org.jboss.samples.webservices;

import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebService;

@Stateless
@WebService()
public class CalcSum {
    
    @WebMethod()
    public int sum(CalcSumInput input) {
        int sum = 0;
        for (int i:input.getInputs()) {
            sum += i;
        }
        
        System.out.println(input.getName() + ":" + sum);
        return sum;
    }

}