C/C++・PHP・PerlからAxis2/Javaの配列を入出力にしたSOAPサービスを呼び出す例
Axis2/Javaのサーバ側
以降は、以下のようなサービスechoStringArrayをAxis2/Javaで作成した場合の話になります。
以下がサーバ側の処理で、これを呼び出すクライアント側の処理をC/C++・PHP・Perlで作成する。C/C++は今回はVC++で。
public class ArrayTest { public String[] echoStringArray(String[] param) { return param; } }
Axis2/Cでスタブを生成して、C/C++で、Axis2/JavaのSOAPサービスを呼び出す。
Axis2/Cのインストール
Axis2/Java 1.4.1にWSDL2Cがない件
Axis2/Cのドキュメントを読むとWSDL2CがAxis2/Javaに入っているように読めるんだけど、ない。
- Apache Axis2/C - Apache Axis2/C - Manual
http://axis.apache.org/axis2/c/core/docs/axis2c_manual.html#wsdl2c
以下に書いてあるように、wsdl2java.batからコピーしてwsdl2c.batを作成し、実行するクラス名を変更すればできる。(しかし、後でちゃんと見たら、wsdl2c.batはAxis2/Cには入っていた。)
- Photo Parata: Where did the WSDL2C Tool go in Axis2/Java 1.4.1?
http://photoparata.blogspot.com/2009/03/where-did-wsdl2c-tool-go-in-axis2java.html
Axis2/Cでのスタブ生成
wsdl2c.batでスタブが生成される。色々と関数が作成されるが、最初は以下の二つの関数を呼び出すところから始めるようだ。
- Building Axis2/C Web Services with the help of Axis2/Java Tools | WSO2 Oxygen Tank
http://wso2.org/library/3534
DLL Load Error 126
コンパイルして、実行すると、以下のようなエラーがAxis2/Cのログに出て、axis2_stub_create_XXXXXXXX()がNULLを返す。(Axis2/Cのログの出力先はaxutil_env_create_all()で指定する。)
[error] ..\..\util\src\class_loader.c(167) Loading shared library C:\axis2c-bin-1.6.0-win32/lib/axis2_http_sender.dll Failed. DLERROR IS DLL Load Error 126: 指定されたモジュールが見つかりません。
「DLL Load Error 126」で検索すると必要なDLLがないらしい。Dependency Walker(depends.exe)というので見ると、LIBEAY32.DLL、SSLEAY32.DLLがないと出てくる。OpenSSLのDLLだそうだ。
コンパイル済みのOpenSSLがあるそうなので、それを入れる。
「Microsoft Visual C++ 2008 再頒布可能パッケージ」を入れてから、Windows Updateもして、「Win32 OpenSSL v1.0.0c Light」を入れる。(しかし日本語の再頒布可能パッケージを入れたせいなのか、入れた後もOpenSSLのインストーラに文句を言われた。)
- Software/OpenSSL for Windows - limber.jp
http://www.limber.jp/?Software%2FOpenSSL%20for%20Windows - cURL - Download
http://curl.haxx.se/download.html#openssl - Shining Light Productions - Win32 OpenSSL
http://www.shininglightpro.com/products/Win32OpenSSL.html - ダウンロードの詳細 : Visual C++ 2008 再頒布可能パッケージ (x86)
http://www.microsoft.com/downloads/details.aspx?FamilyID=9B2DA534-3E03-4391-8A4D-074B9F2BC1BF&displayLang=ja
クライアント側のソース
以下のようなソースでSOAP呼び出しができた。
生成されたスタブにメモリの解放を行うように見える名前の関数もあるのだが、全然使っていないので、問題あるかもしれない。
// Axis2CStub.cpp : コンソール アプリケーションのエントリ ポイントを定義します。 // #include "stdafx.h" #include "axis2_stub_ArrayTest.h" int _tmain(int argc, _TCHAR* argv[]) { axutil_env_t* env = NULL; axis2_char_t* client_home = AXIS2_GETENV("AXIS2C_HOME"); axis2_char_t* endpoint_uri = "endpoint url"; axis2_stub_t* stub = NULL; env = axutil_env_create_all("axis2test.log", AXIS2_LOG_LEVEL_TRACE); stub = axis2_stub_create_ArrayTest(env, client_home, endpoint_uri); if (stub == NULL) { return EXIT_FAILURE; } adb_echoStringArray_t* echoStringArray = adb_echoStringArray_create(env); if (echoStringArray == NULL) { return EXIT_FAILURE; } axis2_char_t* param[] = { "aaa", "bbb", "ccc", "ddd", }; // パラメーターを一つずつ設定する。 for (int i = 0; i < (sizeof(param)/sizeof(param[0])); i++) { axis2_status_t status = adb_echoStringArray_add_param(echoStringArray, env, param[i]); if (status != AXIS2_SUCCESS) { return EXIT_FAILURE; } } adb_echoStringArrayResponse_t* response = NULL; response = axis2_stub_op_ArrayTest_echoStringArray(stub, env, echoStringArray); if (response == NULL) { return EXIT_FAILURE; } axutil_array_list_t* array_list = NULL; array_list = adb_echoStringArrayResponse_get_return(response, env); if (array_list == NULL) { return EXIT_FAILURE; } // 結果データ(文字列の配列)を一つずつ取得する。 int list_size = axutil_array_list_size(array_list, env); for (int i = 0; i < list_size; i++) { void* vp = axutil_array_list_get(array_list, env, i); char* cp = (char*)vp; printf("%s\n", cp); } return EXIT_SUCCESS; }
PHPの場合
PHPが一番簡単だった。事前にスタブを作成する必要はない。また、普通に配列を書いて呼び出せる。SOAPを利用可能にするには以下が必要。
- Windowsならphp.iniでphp_soap.dllを有効にする。
- PHPをコンパイルするなら、configureで--enable-libxml --enable-soapらしい。やってないけど。
<?php try { $client = new SoapClient( 'http://localhost:8080/axis2/services/XXXXXXXX?wsdl', array('soap_version' => SOAP_1_2)); $param = array( "aaaa", "bbbb", "cccc", ); $result = $client->echoStringArray(array( 'param' => $param )); var_dump($result); } catch (SoapFault $f) { print("SoapFault!"); var_dump($f); } ?>
Perlの場合
PerlもPHPと同じようにできるだろうと思っていたが、ちょっと違った。
- SOAP::Liteを入れる必要がある。ppmで入れようとすると依存しているパッケージがいろいろあるみたいなので、全部入れる。
- SOAP::LiteのWSDLのサポートが完全ではないのか、SOAPの入出力のデータ型が配列になっていると処理できないようだった。PHPと同じように以下のようなコードで動くことを期待したが、どうもうまく動かない。文字列の配列ではなく、ただの文字列が渡ってしまう。
以下のようなコードで動くことを期待したが、駄目だった。
use SOAP::Lite +trace => [qw(debug)]; my $service = SOAP::Lite ->service('http://localhost:8080/axis2/services/XXXXXXXX?wsdl'); @param = ( 'aaaa', 'bbbb', 'cccc', ); @result = $service->echoStringArray(@param); print "@result" ."\n";
以下のようにWSDLを使用しないなら何とかなった。以下なら動く。
use SOAP::Lite +trace => [qw(debug)]; my $soap = new SOAP::Lite -> uri('name space uri') -> proxy('endpoint url') ; @param = ( SOAP::Data->name('param')->type(string => 'aaaa'), SOAP::Data->name('param')->type(string => 'bbbb'), SOAP::Data->name('param')->type(string => 'cccc'), ); my $response = $soap->call('echoStringArray' => @param); my $result = $response->result; my @paramsout = $response->paramsout; print "$result @paramsout" ."\n";
Perlはあまり使ったことがないので間違っているかも。