Web サービスを用意する(ASP.NET)
今回は Java のライブラリである Apache Axis を利用してクライアントを作成するため、せっかくなので繋ぎ先は Java 以外で。
Visual Studio 2010 で[新しいプロジェクト] -> [ASP.NET Web アプリケーション]を作成し、
ソリューション エクスプローラーで適当なディレクトリを作成し右クリック -> [追加] -> [新しい項目] -> [Web サービス]を選択。
文字列と数値を受け取って文字列を返すWebサービスを作成。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
namespace WebServices.WS
{
[WebService(Namespace = "http://www.zaneli.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class ZaneliWS : System.Web.Services.WebService
{
[WebMethod(Description="テスト用Webサービスオペレーション")]
public string GetMessage(String text, int num)
{
return "text=" + text + ", num=" + num;
}
}
}
自動生成される WSDL (http://localhost:49175/WS/ZaneliWS.asmx?WSDL)は以下の通り。
2006 年時点で開発は停止し、Axis2 への移行が行われているため今後新規に Axis を選ぶことはあまり無いだろう。
(SOAP Web サービス自体が…というのは置いておいて。)
以下の 5 クラスが自動生成される。
エンジンを入れ替えることで HTTP1.1 での送信が可能になる。 CommonsHTTPSender を使用する場合、commons-httpclient と commons-codec をパスに通す必要がある。
getChunkedOffHeader() で何をやっているのかは次回 Axis2 編で触れる予定。
getSecuritySender() の詳細は今後気が向けばまとめよう。
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:tns="http://www.zaneli.com/"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
targetNamespace="http://www.zaneli.com/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:types>
<s:schema elementFormDefault="qualified" targetNamespace="http://www.zaneli.com/">
<s:element name="GetMessage">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="text" type="s:string" />
<s:element minOccurs="1" maxOccurs="1" name="num" type="s:int" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="GetMessageResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="GetMessageResult" type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
</s:schema>
</wsdl:types>
<wsdl:message name="GetMessageSoapIn">
<wsdl:part name="parameters" element="tns:GetMessage" />
</wsdl:message>
<wsdl:message name="GetMessageSoapOut">
<wsdl:part name="parameters" element="tns:GetMessageResponse" />
</wsdl:message>
<wsdl:portType name="ZaneliWSSoap">
<wsdl:operation name="GetMessage">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">テスト用Webサービスオペレーション</wsdl:documentation>
<wsdl:input message="tns:GetMessageSoapIn" />
<wsdl:output message="tns:GetMessageSoapOut" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="ZaneliWSSoap" type="tns:ZaneliWSSoap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="GetMessage">
<soap:operation soapAction="http://www.zaneli.com/GetMessage" style="document" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:binding name="ZaneliWSSoap12" type="tns:ZaneliWSSoap">
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="GetMessage">
<soap12:operation soapAction="http://www.zaneli.com/GetMessage" style="document" />
<wsdl:input>
<soap12:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap12:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="ZaneliWS">
<wsdl:port name="ZaneliWSSoap" binding="tns:ZaneliWSSoap">
<soap:address location="http://localhost:49175/WS/ZaneliWS.asmx" />
</wsdl:port>
<wsdl:port name="ZaneliWSSoap12" binding="tns:ZaneliWSSoap12">
<soap12:address location="http://localhost:49175/WS/ZaneliWS.asmx" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
ライブラリのダウンロード
Apache Axis サイトから axis-bin-1_4 をダウンロードする。2006 年時点で開発は停止し、Axis2 への移行が行われているため今後新規に Axis を選ぶことはあまり無いだろう。
(SOAP Web サービス自体が…というのは置いておいて。)
スタブを使用して Web サービス実行
WSDL2Java コマンドで WSDL からスタブを生成する。java org.apache.axis.wsdl.WSDL2Java http://localhost:49175/WS/ZaneliWS.asmx?WSDL以下の 5 クラスが自動生成される。
- com.zaneli.www.ZaneliWS
- com.zaneli.www.ZaneliWSLocator
- com.zaneli.www.ZaneliWSSoap
- com.zaneli.www.ZaneliWSSoap12Stub
- com.zaneli.www.ZaneliWSSoapStub
import java.rmi.RemoteException;
import javax.xml.rpc.ServiceException;
import com.zaneli.www.ZaneliWS;
import com.zaneli.www.ZaneliWSLocator;
import com.zaneli.www.ZaneliWSSoap;
public class AxisExecutor1 {
public String execute(String text, int num) throws ServiceException, RemoteException {
ZaneliWS service = new ZaneliWSLocator();
ZaneliWSSoap port = service.getZaneliWSSoap();
return port.getMessage(text, num);
}
public static void main(String[] args) throws ServiceException, RemoteException {
System.out.println(new AxisExecutor1().execute("Axisで実行", 111));
}
}
「text=Axisで実行, num=111」が出力されることを確認。スタブを使用せず Web サービス実行
WSDL の URL, サービス名, ポート名, オペレーション名を直接指定する場合は以下のようにする。
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import javax.xml.namespace.QName;
import javax.xml.rpc.Call;
import javax.xml.rpc.ServiceException;
import org.apache.axis.client.Service;
public class AxisExecutor2 {
private static final String WSDL_URI = "http://localhost:49175/WS/ZaneliWS.asmx?WSDL";
private static final String NAMESPACE = "http://www.zaneli.com/";
private static final QName SERVICE_NAME = new QName(NAMESPACE, "ZaneliWS");
private static final QName PORT_NAME = new QName(NAMESPACE, "ZaneliWSSoap");
private static final String OPERATION_NAME = "GetMessage";
public String execute(String text, int num) throws MalformedURLException, ServiceException, RemoteException {
Service service = new Service(new URL(WSDL_URI), SERVICE_NAME);
Call call = service.createCall(PORT_NAME, OPERATION_NAME);
return (String) call.invoke(new Object[]{text, num});
}
public static void main(String[] args) throws ServiceException, RemoteException, MalformedURLException {
System.out.println(new AxisExecutor2().execute("Axisで動的実行", 222));
}
}
「text=Axisで動的実行, num=222」が出力されることを確認。エンジンを入れ替える
Axis では HTTP1.0 で SOAP リクエストを送信しているが、エンジンを入れ替えることで HTTP1.1 での送信が可能になる。 CommonsHTTPSender を使用する場合、commons-httpclient と commons-codec をパスに通す必要がある。
import java.rmi.RemoteException;
import java.util.Hashtable;
import javax.xml.rpc.ServiceException;
import org.apache.axis.AxisEngine;
import org.apache.axis.SimpleTargetedChain;
import org.apache.axis.client.AxisClient;
import org.apache.axis.configuration.SimpleProvider;
import org.apache.axis.transport.http.CommonsHTTPSender;
import org.apache.axis.transport.http.HTTPConstants;
import org.apache.axis.transport.http.HTTPTransport;
import com.zaneli.www.ZaneliWS;
import com.zaneli.www.ZaneliWSLocator;
import com.zaneli.www.ZaneliWSSoap;
public class AxisExecutor1 {
public String execute(String text, int num) throws ServiceException, RemoteException {
ZaneliWS service = new ZaneliWSLocator();
((org.apache.axis.client.Service) service).setEngine(getEngine());
ZaneliWSSoap port = service.getZaneliWSSoap();
return port.getMessage(text, num);
}
private AxisEngine getEngine() {
CommonsHTTPSender sender = new CommonsHTTPSender();
SimpleProvider clientConfig = new SimpleProvider();
clientConfig.deployTransport(
HTTPTransport.DEFAULT_TRANSPORT_NAME,
new SimpleTargetedChain(sender));
AxisClient engine = new AxisClient(clientConfig);
engine.setOption(HTTPConstants.REQUEST_HEADERS, getChunkedOffHeader());
return engine;
}
private Hashtable<String, Boolean> getChunkedOffHeader() {
Hashtable<String, Boolean> httpHeaders = new Hashtable<String, Boolean>();
httpHeaders.put(HTTPConstants.HEADER_TRANSFER_ENCODING_CHUNKED, false);
return httpHeaders;
}
public static void main(String[] args) throws ServiceException, RemoteException {
System.out.println(new AxisExecutor1().execute("Axisで実行", 111));
}
}
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import java.util.Hashtable;
import javax.xml.namespace.QName;
import javax.xml.rpc.Call;
import javax.xml.rpc.ServiceException;
import org.apache.axis.AxisEngine;
import org.apache.axis.SimpleTargetedChain;
import org.apache.axis.client.AxisClient;
import org.apache.axis.client.Service;
import org.apache.axis.configuration.SimpleProvider;
import org.apache.axis.transport.http.CommonsHTTPSender;
import org.apache.axis.transport.http.HTTPConstants;
import org.apache.axis.transport.http.HTTPTransport;
public class AxisExecutor2 {
private static final String WSDL_URI = "http://localhost:49175/WS/ZaneliWS.asmx?WSDL";
private static final String NAMESPACE = "http://www.zaneli.com/";
private static final QName SERVICE_NAME = new QName(NAMESPACE, "ZaneliWS");
private static final QName PORT_NAME = new QName(NAMESPACE, "ZaneliWSSoap");
private static final String OPERATION_NAME = "GetMessage";
public String execute(String text, int num) throws MalformedURLException, ServiceException, RemoteException {
Service service = new Service(new URL(WSDL_URI), SERVICE_NAME);
service.setEngine(getEngine());
Call call = service.createCall(PORT_NAME, OPERATION_NAME);
call.setProperty(HTTPConstants.REQUEST_HEADERS, getChunkedOffHeader());
return (String) call.invoke(new Object[]{text, num});
}
private AxisEngine getEngine() {
SimpleProvider clientConfig = new SimpleProvider();
clientConfig.deployTransport(
HTTPTransport.DEFAULT_TRANSPORT_NAME,
new SimpleTargetedChain(new CommonsHTTPSender()));
return new AxisClient(clientConfig);
}
private Hashtable<String, Boolean> getChunkedOffHeader() {
Hashtable<String, Boolean> httpHeaders = new Hashtable<String, Boolean>();
httpHeaders.put(HTTPConstants.HEADER_TRANSFER_ENCODING_CHUNKED, false);
return httpHeaders;
}
public static void main(String[] args) throws ServiceException, RemoteException, MalformedURLException {
System.out.println(new AxisExecutor2().execute("Axisで動的実行", 222));
}
}
getEngine() で CommonsHTTPSender を設定するようにしている。getChunkedOffHeader() で何をやっているのかは次回 Axis2 編で触れる予定。
WS-Securityに対応する
Apache WSS4Jを使用し、エンジン設定の際に
private AxisEngine getEngine() {
CommonsHTTPSender sender = new CommonsHTTPSender();
SimpleProvider clientConfig = new SimpleProvider();
clientConfig.deployTransport(
HTTPTransport.DEFAULT_TRANSPORT_NAME,
new SimpleTargetedChain(sender));
AxisClient engine = new AxisClient(clientConfig);
engine.setOption(HTTPConstants.REQUEST_HEADERS, getChunkedOffHeader());
clientConfig.setGlobalRequest(getSecuritySender());
return engine;
}
と指定すれば設定可能。getSecuritySender() の詳細は今後気が向けばまとめよう。