SOAP::Liteモジュール (SOAP::Lite v.0.50)(日本語チョー訳)

by Hippo2000(2001/5/23,2002/5/25)

SOAP::Liteモジュールなのです。ホームページはSOAPLITE.COM http://soaplite.com/ になります。
ここにはユーザーガイド(http://guide.soaplite.com/)、クックブック( http://cookbook.soaplite.com/)があります。
こちらの情報についてはこれからチョー訳を考えたいと思っています。

なおこのSOAP-Liteのディストリビューションには以下のドキュメントも入っています。
合わせてご覧ください。

ファイル/モジュール 説 明
Apache::SOAP 最小限の設定でSOAPサーバーの機能を提供
SOAP::Test SOAP::Liteのためのテスト・フレームワーク
SOAP::Transport::FTP SOAP::Liteのためのクライアント側FTPサポート
SOAP::Transport::HTTP SOAP::Liteのためのサーバ/クライアント側HTTPサポート
SOAP::Transport::IO SOAP::Lite のサーバー側IOサポート
SOAP::Transport::LOCAL SOAP::Liteのためのクライアント側での転送なしのサポート
SOAP::Transport::MAILTO SOAP::Liteのためのクライアント側 SMTP/sendmail サポート
SOAP::Transport::POP3 SOAP::Liteのためのサーバー側POP3サポート
SOAP::Transport::TCP SOAP::Liteのためのサーバー/クライアント側TCPサポート
SOAPsh.pl SOAP呼び出しのための対話的なシェル
UDDI::Lite PerlでのUDDIクライアントのためのライブラリ
XML::Parser::Lite 正規表現ベースの軽いXMLパーザー
XMLRPC::Lite XML-RPCプロトコルのクライアントとサーバーの実装
XMLRPC::Transport::HTTP XMLRPC::Liteのためのサーバー/クライアント側 HTTPサポート
XMLRPCsh.pl XML RPC呼び出しの対話的なシェル

なおこのドキュメントはCPAN-Searchで出てきたドキュメント(PODを変換したもの)を日本語に訳そうとしたものです。わかりにくい部分は本物を見てください。(^^;;

原本の著作権はPaul Kulchenko さんがお持ちです。
Paul Kulchenko さんにはメールで了解をいただきました。

なお内容等が間違っていたら修正します。ご連絡ください。

=更新履歴=


目次


名前

SOAP::Lite - クライアントおよびサーバー側SOAP実装


概要

  use SOAP::Lite;
  print SOAP::Lite
    -> uri('http://www.soaplite.com/Temperatures')
    -> proxy('http://services.soaplite.com/temper.cgi')
    -> f2c(32)
    -> result;
 

同じことをautodispatchで:

  use SOAP::Lite +autodispatch =>
    uri => 'http://www.soaplite.com/Temperatures',
    proxy => 'http://services.soaplite.com/temper.cgi';

  print f2c(32);

OOスタイルのコード:

  use SOAP::Lite +autodispatch =>
    uri => 'http://www.soaplite.com/Temperatures',
    proxy => 'http://services.soaplite.com/temper.cgi';

  my $temperatures = Temperatures->new(32); # オブジェクトの取得
  print $temperatures->as_celsius;          # メソッドの呼び出し

サービス説明つきのコード:

  use SOAP::Lite;
  print SOAP::Lite
    -> service('http://www.xmethods.net/sd/StockQuoteService.wsdl')
    -> getQuote('MSFT');

SOAPサーバーのためのコード(CGI):

  use SOAP::Transport::HTTP;
  SOAP::Transport::HTTP::CGI
    -> dispatch_to('/Your/Path/To/Deployed/Modules', 'Module::Name', 'Module::method') 
    -> handle;

Visual Basic クライアント(COMインターフェースを通して):

  MsgBox CreateObject("SOAP.Lite").new( _
    "proxy", "http://services.xmethods.net/soap", _
    "uri",   "urn:xmethods-delayed-quotes" _
  ).getQuote("MSFT").result

mod_soap はSOAPサーバーを可能にします:

  .htaccess

  SetHandler perl-script
  PerlHandler Apache::SOAP
  PerlSetVar dispatch_to "/Your/Path/To/Deployed/Modules, Module::Name"

ASP/VB SOAP サーバー:

  <%
    Response.ContentType = "text/xml"
    Response.Write(Server.CreateObject("SOAP.Lite") _
      .server("SOAP::Server") _ 
      .dispatch_to("/Your/Path/To/Deployed/Modules") _
      .handle(Request.BinaryRead(Request.TotalBytes)) _
    )
  %>


説明

SOAP::Lite はクライアント、サーバー側の両方でSimple Object Access Protocol (SOAP)への簡単で軽いインターフェースを提供するPerlモジュールの集まりです。

このバージョンのSOAP::LiteはSOAP1.1仕様( http://www.w3.org/TR/SOAP )をサポートしています。

このライブラリの主な機能は以下のとおりです:

例がある場所

クライアント側の例についてはt/*.t, examples/*.pl そしてモジュール・ドキュメントをご覧ください。SOAPリクエストのシリアライゼーション、HTTP経由でサーバーへの送信、レスポンスの受信そしてレスポンスのデシリアライゼーションをデモンストレートしています。サーバー側の実装についてはexamples/server/* をご覧ください。


クラスとパッケージの概要

このライブラリにより提供されるクラスの概要を以下の表にしめします:

 SOAP::Lite.pm
 -- SOAP::Lite           -- すべてのロジックを提供するメイン・クラス
 -- SOAP::Transport      -- 転送アーキテクチャをサポート
 -- SOAP::Data           -- シリアライゼーション・アーキテクチャのための拡張を提供
 -- SOAP::Header         -- ヘッダ・シリアライゼーションのための拡張を提供
 -- SOAP::Parser         -- XMLファイルを解析し、オブジェクト・ツリーにします
 -- SOAP::Serializer     -- データ構造をSOAPパッケージにシリアル化
 -- SOAP::Deserializer   -- SOAP::Parserの結果をオブジェクトにデシリアル化
 -- SOAP::SOM            -- デシリアライズされたオブジェクト・ツリーへのアクセスを提供
 -- SOAP::Constants      -- 共通定数へのアクセスを提供
 -- SOAP::Trace          -- トレース機能を提供
 -- SOAP::Schema         -- スキーまのためのアクセスとスタブを提供
 -- SOAP::Schema::WSDL   -- SOAP::SchemaのためのWSDL実装
 -- SOAP::Server         -- サーバー側でのリクエストを取り扱う
 -- SOAP::Server::Object -- 参照によるオブジェクトを取り扱う
 -- SOAP::Fault          -- サーバー側でのFaultsのサポートを提供

 SOAP::Transport::HTTP.pm
 -- SOAP::Transport::HTTP::Client  -- HTTP 転送へのクライアント・インターフェース
 -- SOAP::Transport::HTTP::Server  -- HTTP 転送へのサーバー・インターフェース
 -- SOAP::Transport::HTTP::CGI     -- サーバー・インターフェースのCGI 実装
 -- SOAP::Transport::HTTP::Daemon  -- サーバーインターフェースのデーモン実装
 -- SOAP::Transport::HTTP::Apache  -- サーバー・インターフェースのmod_perl実装

 SOAP::Transport::POP3.pm
 -- SOAP::Transport::POP3::Server  -- POP3 プロトコルへのサーバー・インターフェース

 SOAP::Transport::MAILTO.pm
 -- SOAP::Transport::MAILTO::Client -- SMTP/sendmailへのクライアント・インターフェース

 SOAP::Transport::LOCAL.pm
 -- SOAP::Transport::LOCAL::Client -- ローカルな転送へのクライアント・インターフェース

 SOAP::Transport::TCP.pm
 -- SOAP::Transport::TCP::Server -- TCPプロトコルへのサーバー・インタフェース
 -- SOAP::Transport::TCP::Client -- TCPプロトコルへのクライアント・インターフェース

 SOAP::Transport::IO.pm
 -- SOAP::Transport::IO::Server -- IO転送へのサーバー・インターフェース

SOAP::Lite

SOAP::Liteが提供するすべてのメソッドは値の設定と取り出しの両方のために使うことができます。なにもパラメータを与えなければ、現在の値を取得することができます。そしてパラメータが与えられると新しい値がオブジェクトに代入され、問題のメソッドは(他に何も書かれてなければ)現在のオブジェクトを返します。これは呼び出しを以下のように積み重ねるのに便利です。

  $lite = SOAP::Lite
    -> uri('http://simon.fell.com/calc')
    -> proxy('http://soap.4s4c.com/ssss4c/soap.asp')
  ;

順番はあまり重要ではなく、最初にnew()メソッドを呼び出すことができます。そうしなければSOAP::Liteはあなたに代わって、それをします。しかしnew()メソッドは追加の書き方を提供します:

  $lite = new SOAP::Lite
    uri => 'http://simon.fell.com/calc',
    proxy => 'http://soap.4s4c.com/ssss4c/soap.asp'
  ;

new()
new() はメソッド名をキーとするハッシュを受け取ります。それは渡された値で適切なメソッドを一緒に呼び出します。new()はオプションなので、これについてはこれ以上、述べません。
transport()
"SOAP::Transport" オブジェクトへのアクセスを提供します。そのオブジェクトはあなたのために作成されます。それを再度代入することができます。(しかし通常はそうするべきではありません)
serializer()
"SOAP::Serialization"オブジェクトへのアクセスを提供します。そのオブジェクトはあなたのために作成されます。それを再度代入ることができます。(しかし通常はそうするべきではありません)
proxy()
transport->proxy()のショートカット。これはエンドポイント(サービス・アドレス)を指定させます、そして同時に必要なモジュールをロードします。SOAP呼び出しをdispatchさせるために必要です。モジュールの名前はエンドポイントに特有のプロトコルに依存して決まります。接頭語SOAP::Transport がprependedされるでしょう、モジュールがロードされ、クラスのオブジェクト(::Clientが後ろについて)が作成されます。
例えば、http://localhost/では、オブジェクトを作るためのクラスは SOAP::Transport:HTTP::Clientで探されます。

エンドポイント・パラメータに加えて、 proxy() は名前=>値で渡された転送特有のパラメータを受け取ることができます。例えばHTTPプロトコルのためのプロキシー設定を指定するには、以下のようにすることができます:

  $soap->proxy('http://endpoint.server/', 
               proxy => ['http' => 'http://my.proxy.server/']);

プロキシー(2番目のもの)は1つ以上のパラメータを取ることを予想しているので、それらを配列にくるまなけばならないことに注意してください。

もう1つの便利な例はクッキー・ベースの認証を感知するクライアントにすることができます。それは以下のようにします:

  $soap->proxy('http://localhost/', 
               cookie_jar => HTTP::Cookies->new(ignore_discard => 1));

以下のようにしてHTTP転送のためにタイムアウトを指定することができます:

  $soap->proxy('http://localhost/', timeout => 5);

endpoint()
プロトコル・モジュールを変更/ロードすることなしにエンドポイントを指定させます。これはプロトコルの切り替えなしにエンドポイントを切り替えるのに便利です。最初にproxy()を呼ばなければなりません。プロトコルが同じであるかのチェックは何もされません。
outputxml()
すべてのメソッド呼び出しからの出力の種類を指定させます。もしtrueであれば、すべてのメソッドは処理されない生のXMLコードを返します。それをXML::Parser、SOAP::Deserializerあるいは他の適切なモジュールで解析することができます。
autotype()
serializer->autotype()のショートカット。これはシリアライザがあなたに代わって自動タイピングをするかどうかを指定させます。デフォルトの設定はtrueです。
readable()
serializer->readable()のショートカット。これは作成されるXMLコードのためのフォーマットを指定させます。改行(<CR>)とインデントが読みやすさのためにに加えられます。生成されたコードをデバッガで見たい場合に便利です。デフォルトでは生成されたXMLk−ドに何も追加の文字はありません。
namespace()
serializer->namespace()の.ショートカット。生成されるエンベロープのデフォルトの名前空間を指定させます。 (デフォルトでは'SOAP-ENV' )。
encodingspace()
serializer->encodingspace()のショートカット。生成されるエンベロープのためのデフォルトのエンコーディング名前空間を指定させます(デフォルトは'SOAP-ENC'
encoding()
serializer->encoding()のショートカット。生成されたエンベロープのためのエンコーディングを指定させます。現在のところ、実際にはエンベロープのエンコーディングを変更せず、XMLヘッダを変更するだけです(デフォルトでは'UTF-8')
typelookup()
serializer->typelookup()のショートカット。自動タイピングのために使われるtypelookup テーブルへのアクセスを提供します。詳細については"SOAP::Serializer"をご覧ください。
uri()
serializer->uri()のショートカット。SOAPメソッドのためのuriを指定させます。デフォルトでは何も指定されません。必要なuriを指定しなければ、呼び出しは間違いなく失敗するでしょう。

警告: URI は単なる識別子です。URLのように見えるかもしれませんが、どこかをさしている保証はありませんし、そのようなポインタのように扱われるべきでもありません。URIはすべてのXMLドキュメントの空間においてユニークであると仮定されます。そこでユニークな識別子以外の何者でもないと考えられます。

multirefinplace()

serializer->multirefinplace()のショートカット。もしtrueであれば、シリアライザは最初のリファレンスの並びで多重参照(multireferences)のための値を出力します。そうでなければ、Bodyの中のmethod要素の直ぐ後にトップの独立要素としてエンコードされます。デフォルトの値はfalse。
header()
廃棄予定: 代わりにSOAP::Header を使ってください。

serializer->header()のショートカット。生成されるエンベロープのヘッダを指定させます。"SOAP::Data"クラスを使って、root, mustUnderstand またはそれ以外のすべてのヘッダを指定することができます。

  $serializer = SOAP::Serializer->envelope('method' => 'mymethod', 1,
    SOAP::Header->name(t1 => 5)->mustUnderstand(1),
    SOAP::Header->name(t2 => 7)->mustUnderstand(2),
  );

これは以下のようにシリアライズされます:

  <SOAP-ENV:Envelope ...attributes skipped>
    <SOAP-ENV:Header>
      <t1 xsi:type="xsd:int" SOAP-ENV:mustUnderstand="1">5</t1>
      <t2 xsi:type="xsd:int" SOAP-ENV:mustUnderstand="1">7</t2>
    </SOAP-ENV:Header>
    <SOAP-ENV:Body>
      <namesp1:mymethod xmlns:namesp1="urn:SOAP__Serializer">
        <c-gensym6 xsi:type="xsd:int">1</c-gensym6>
      </namesp1:mymethod>
    </SOAP-ENV:Body>
  </SOAP-ENV:Envelope>

SOAP::Header パラメータを他のパラメータに混ぜることができます。またリモート呼び出しの結果としてSOAP::Header を返すこともできます。例としてMy::Parameters::addheadertをご覧ください。

on_action()

on_actionイベントのためのハンドラを指定させます。これはSOAPActionが作成されたときに発生します。デフォルトのハンドラはSOAPActionを"uri#method"に設定します。この動きをグローバルに("デフォルト設定"をご覧ください)、もしくは特定のオブジェクトのためにローカルに変更することができます。
on_fault()
on_faultイベントのためのハンドラを指定させます。デフォルトの動きは転送エラーではdieし、そのほかのエラー状態では何もしません。この動きをグローバルに("デフォルト設定"をご覧ください)、もしくは特定のオブジェクトのためにローカルに変更することができます。
on_debug()
on_debugイベントのためのハンドラを指定させます。デフォルトの動きは何もしません。代わりにSOAP::Liteのための+trace/+debugオプションを使ってください。、もし使って警告されると、このメソッドは単なる+trace/+debugへのインターフェースでグローバルな影響をもつので、もし1つのオブジェクトのためにインストールすると、後のすべての呼び出しについて影響がありす(他のオブジェクトについてさえも)。
on_nonserialized()
on_nonserializedイベントへのハンドラを指定させます。デフォルトの動きは、(CODEリファレンスやGLOBのように).適切にシリアライズできないものがあるたびに警告(wanining)がonがあれば警告が生成されます。
call()
リモート・メソッド呼び出しのための代替インタフェースを提供します。いつでもSOAP::Lite->new(...)->method->(@parameters)で実行できますが、call()は追加のオプションをいくつか提供します:
接頭辞のついたメソッド
生成されたメソッドの要素のための接頭辞を指定したければ、call()インターフェースで行うことも利用可能な選択肢の1つです。
  print SOAP::Lite
    -> new(....)
    -> call('myprefix:method' => @parameters)
    -> result;

この例はクライアント側でのみ機能します。サーバー側で接頭辞を変更したければ、デフォルトのシリアライザをオーバーライドする必要があります。例はexamples/server/soap.* をご覧ください。

すべてのメソッドへのアクセス

何らかの理由でSOAP::Liteのメソッドと同じ名前をもつリモート・プロシージャへアクセスしたいならば、これらの呼び出しは(明らかに)呼び出されません。この場合にはcall()を通して呼び出すことでおこなうことができます。
  print SOAP::Lite
    -> new(....)
                   # 最初のパラメータでCLASS名を指定することを忘れないでください。
    -> call(new => @parameters) 
    -> result;

OOインターフェースの実装
autodispatch ではCLASS/OBJECT 呼び出しを以下のようにすることができます:
  my $obj = CLASS->new(@parameters);
  print $obj->method;

しかしautodispatch の副作用として、代わりにcall()を使って以下のような書き方も可能です:

  # uri()を指定しなければなりません
  my $soap = SOAP::Lite
    -> uri('http://my.own.site/CLASS') # <<< CLASS goes here
    # ..... その他のパラメータ
  ;

  my $obj = $soap->call(new => @parameters)->result;
  print $soap->call(method => $obj)->result;
  # 必要であれば$obj オブジェクトはここでは更新されません、
  # $obj->method()tmethod()が$objを更新するように

  # 変更されたオブジェクトの更新はサーバーがSOAP::Liteではない別の場所にあれば
  # 動かないかも知れません

メソッドの属性の設定する能力
さらに以下のような書き方でメソッド要素の属性を指定することができます:
  print SOAP::Lite
    -> new(....)
    -> call(SOAP::Data->name('method')->attr({xmlns => 'mynamespace'})
            => @parameters)
    -> result;

すべての属性とメソッドの名前になるSOAP::Data要素の名前を指定することができます。属性を除いては無視され、パラメータは通常どおりに提供されます。

このメソッドを使ってより多くの制御ができますが、先にuri()呼び出しをしていたとしても明示的にメソットのため名前空間属性を指定しなければならないことに注意してください。そのためメソッド要素に名前空間を持っていなければならないならば、以下のような代わりに

  print SOAP::Lite
    -> new(....)
    -> uri('mynamespace') # will be ignored 
    -> call(SOAP::Data->name('method') => @parameters)
    -> result;

このようにしてください

  print SOAP::Lite
    -> new(....)
    -> call(SOAP::Data->name('method')->attr({xmlns => 'mynamespace'})
            => @parameters)
    -> result;

前の呼び出しでのuri()は無視され、名前空間は指定されません。(推奨されるように)-wオプションをつけてスクリプトを実行すると以下のような警告がでます:

  URI is not provided as attribute for method (method)

さらにプレフィックスをつけて呼び出そうとすると致命的なエラーになります:

  print SOAP::Lite
    -> new(....)
    -> uri('mynamespace') # will be ignored 
    -> call(SOAP::Data->name('a:method') => @parameters)
    -> result;

これは以下のようになります:

  Can't find namespace for method (a:method)

というのも何もプレフィックス'a'に結び付けられていないからです

さらにもう1つコメント。SOAP::Liteがあなたが指定したものを変更してしまう1つのケースにはプレフィックス付の名前を指定し、名前空間名を指定しなときがあります:

  print SOAP::Lite
    -> new(....)
    -> uri('') 
    -> call('a:method' => @parameters)
    -> result;

これは以下のようなものを生成します:

  <method xmlns="">....</method>

このようにではありません

  <a:method xmlns:a="">....</method>

というのも後者はXML名前空間の仕様上、許されないからです。

他のすべての点では->call(mymethod => @parameters)->mymethod(@parameters)と同義語です。

self()

use SOAP::Lite ... インターフェースで指定されたグローバルなデフォルト・オブジェクトへのオブジェクト・リファレンスを返します。クラス・メソッドとオブジェクト・メソッドの両方ともグローバルオブジェクトへのリファレンスを返します、そのため:
  use SOAP::Lite
    proxy => 'http://my.global.server'
  ;

  my $soap = SOAP::Lite->proxy('http://my.local.server');

  print $soap->self->proxy;

これは 'http://my.global.server' (SOAP::Lite->self->proxyと同様に)を出力します。詳細は"デフォルト設定" をご覧ください。

dispatch_from()
autodispatch がするのとまったく同じことをします。しかし UNIVERSAL::AUTOLOADハンドラをインストールせず、指定されたクラスでAUTOLOADハンドラのみをインストールします。use SOAP::Lite ... 節でしか使うことができません、そして最初に指定されなければなりません:
  use SOAP::Lite 
    dispatch_to => ['A', 'B'], # 1つのクラスには "dispatch_to => 'A'" としてください
    uri => ....,
    proxy => ....,
  ;

  A->a;
  B->b;

SOAP::Data

SOAP要素に値、名前、型、uri、属性を指定したいときにこのクラスを使うことができます(それぞれvalue(), name(), type(), uri() and attr() メソッドを使って)。例えば、SOAP::Data->name('abc')->value(123)は<abc>123</abc>にシリアライズされます。またSOAP::Data->name(abc=>123)とすることもできます。(value()メソッドを除いて)それぞれは値を2番目のパラメータとして受け取ることができます。すべてのメソッドはパラメータがなしで呼び出すと、現在の値を返します。そうでなければそのオブジェクトが返されるので、それらを重ねることができます。さらなる例はtestsをご覧ください。これらのメソッドを以下のようにしてインポートすることができます:

  SOAP::Data->import('name'); 

または

  import SOAP::Data 'name'; 

そして短く name(abc => 123) とすることができます。

特定の要素のためのインターフェースも提供されています。ctor(), mustUnderstand(), encodingStyle() そして root() を対応する属性の値を設定/取得するために使うことができます。

  SOAP::Data
    ->name(c => 3)
    ->encodingStyle('http://xml.apache.org/xml-soap/literalxml')

これは以下のようにシリアライズされます:

  <c SOAP-ENV:encodingStyle="http://xml.apache.org/xml-soap/literalxml"
     xsi:type="xsd:int">3</c>

SOAP::Serializer

通常はこのモジュールと直接対話する必要はありません。必要な唯一のケースは自動タイピングを使うときです。この機能は(例えば順序付のハッシュのような)新しいデータ型を導入したい、あなたの必要にしたがってデータのための型を指定させます。

SOAP::Data->type(float => 123)で型を指定することができます。シリアライゼーションの段階では、モジュールはas_floatメソッドでデータをシリアル化しようとします。それがtypecastメソッドを呼び出すと(オーバーライドしたり"SOAP::Data"から継承することができます)データ型(SCALAR、ARRAYまたはHASH)に従っってそれをシリアライズしようとします。例えば:

  SOAP::Data->type('ordered_hash' => [a => 1, b => 2]) 

これはas_ordered_hashメソッドを使って、順序付のハッシュといしてシリアライズされます。

直接、型を指定しなければ、serialization モジュールはtypelookupハッシュに従って、あなたの代わりに自動判定しようとします。そのtypelookupハッシュには型名をキーとし以下の3つの要素の配列が値として入っています:

  優先順位、 
  チェック関数(コードリファレンス)、 
  typecast関数 (メソッド名もしくはコード・リファレンス)

例えばuriReferenceを自動判定される型に追加したければ、以下のようなものを追加しなければなりません:

  $s->typelookup->{uriReference} =
    [11, sub { $_[0] =~ m!^http://! }, 'as_uriReference'];

そして"SOAP::Serializer"クラスにas_uriReferenceメソッドを追加します:

  sub SOAP::Serializer::as_uriReference {
    my $self = shift;
    my($value, $name, $type, $attr) = @_;
    return [$name, {'xsi:type' => 'xsd:uriReference', %$attr}, $value];
  }

指定されたメソッドは自動タイピングでも直接データ型設定でも使われます。そのため以下のいずれも使うことができます:

  SOAP::Data->type(uriReference => 'http://yahoo.com')>

もしくは単に

  'http://yahoo.com'

そしてそれらは同じ型にシリアライズされます。さらなる例については"SOAP::Serializer"でのas_*メソッドをご覧ください。

SOAP::Serializer はautotype(), readable(), namespace(), encodingspace(), encoding(), typelookup(), uri(), multirefinplace() そしてenvelope()メソッドを提供します。すべてのメソッドは(envelope()を除いて). All methods (except envelope()) "SOAP::Lite"で説明されています。

envelope()
このメソッドは最初のパラメータによって3種類のエンベロープを組み立てることを可能にします。
method
  envelope(method => 'methodname', @parameters);
もしくは
  method('methodname', @parameters);

はrequest/response エンベロープを組み立てます。

fault
  envelope(fault => 'faultcode', 'faultstring', $details);
もしくは
  fault('faultcode', 'faultstring', $details);

はfaultエンベロープを組み立てます。Faultcode は適切に修飾され、detailsには文字列またはオブジェクトを指定できます。

freeform
  envelope(freeform => 'something that I want to serialize');

または
  freeform('something that I want to serialize');
           

非RPC呼び出し他のための予約。SOAPエンベロープの内側に独自の情報を組み立てさせます。メソッド特有のものを除いて、すべてのSOAP1.1仕様規則が強制されます。例としてUDDI::Liteをご覧ください。

さらなる例としてはtestsとSOAP::Transport::HTTP.pmをご覧ください。

SOAP::SOM

オブジェクト指向インタフェースを通じて行うすべての呼び出しは、SOAP::SOMオブジェクトを返します。そしてそれで実際の値にアクセスすることができます。次の例はそのクラスの簡単な概要を示します:

  my $soap = SOAP::Lite .....;
  my $som = $soap->method(@parameters);
  if ($som->fault) { # もしFault要素がそのメッセージにあればdefined
    print $som->faultdetail; # 文字列またはオブジェクトとして
                             # 'detail'要素の値を返します
    $som->faultcode;   #
    $som->faultstring; # 同様に使えます
    $som->faultactor;  # 
  } else {
    $som->result; # 呼び出し結果へのアクセスを提供します
                  # あらゆるデータ構造になりえます。例えばreturn [1,2]のようにサーバーが
                  # したとすれば配列へのリファレンスになります
  
    $som->paramsout; # もしあればoutパラメータへのアクセスを提供します。
                     # 例えば、サーバーがreturns ([1,2], 1, 2); であれば
                     # 配列(1,2)を取得するでしょう。 
                     # [1,2] は$som->resultとして返されます。
                     # $som->paramsall は ([1,2], 1, 2) を返します。
                     # さらなる詳細はセクション IN/OUT, OUT パラメータと自動バインディング
                     # をご覧ください

    $som->paramsall; # 結果と(もしあれば)outパラメータへのアクセスを与え、
                     # 1つの配列として返します
  
    $som->valueof('//myelement'); # もしあれば'myelement'の値(perlデータとして)
                                  # 返します。配列コンテキストではすべての要素、
                                  # スカラコンテキストでは最初の要素を返します
  
    $h = $som->headerof('//myheader'); # SOAP::Headerとして要素を返します。そのため
                                       # 属性や値に$h->mustUnderstand, $h->actor
                                       # または$h->attr (すべての属性用)でアクセスする
                                       # ことができます。
  }
   

SOAP::SOM オブジェクトは数種類のメソッドを通して、デシリアライズされたエンベロープへのアクセスを提供します。すべてのメソッドは(XPathの書き方に似ている)ノード・パスを受け取ります。

SOMは'/'をルート・ノード、'//'を相対的位置パス('/Envelope//nums'はEnvelopeノードの下にあるすべての'nums'ノードを見つけるのと同様に、'//Body'はドキュメントのなかのすべての本体(body)を探します)、'{num}はノード番号、そしてopを持った'[op num]'は比較演算子('<', '>', '<=', '>=', '!', '=')であると解釈します。

ノードセットでのすべてのノードはドキュメントでの順番に返されます。

match()
ノードへのパスを受け取り、ブール値コンテキストではtrue/falseを返し、それ以外ではSOMオブジェクトを返します。valueof()とdataof()はマッチしたノードの値を取得するために使うことができます。
valueof()
(以前に)マッチしたノードの値を返します。これはノード・パスを受け取ります。この場合、マッチしたノードの値を返します。しかし現在のノードを変更しません。ノードにマッチさせノードの子供を探るときに便利です:
  $som->match('/Envelope/Body/[1]'); # match メソッド
  $som->valueof('[1]');              # 結果
  $som->valueof('[2]');              # 最初のout パラメータ (もしあれば)

返される値はコンテキストに依存します。スカラ・コンテキストではマッチしたノードセットから最初の要素を返します。配列コンテキストではマッチしたすべての要素を返します。

dataof()

valueof()と同じ。しかし"SOAP::Data" オブジェクトを返します。そのため要素の名前、型、属性にアクセスすることができます。
headerof()
dataof()と同じ。しかし"SOAP::Header" オブジェクトを返します。そのため要素の名前、型、属性にアクセスすることができます。ヘッダを変更するためにも使うことができます(Header要素の内側の更新されたヘッダを見たければ、dataof()メソッドの代わりにこのメソッドをつかったほうがよいです)。
namespaceuriof()
マッチした要素に結び付けられたuriを返します。このuri は継承させることもできます。例えば以下のようなものを持っていたとします:
  <a xmlns='http://my.namespace'>
    <b>
       value
    </b>
  </a>

このメソッドは'a'のためと同じ値を'b'についても返します。

SOAP::SOMはエンベロープ(envelope)、本体(body)、メソッド(method)そしてパラメータ(parameter)(inとoutの両方)への直接アクセスするメソッドも提供します。オブジェクト・メソッドとして呼ばれると、これらすべてのメソッドは本当の値を返します(ほとんどの場合それはハッシュ・リファレンスになります)。返される値はコンテキストによります:配列コンテキストでは値の配列を返します。そしてスカラ・コンテキストでは最初の要素を返します。そのため最初の出力パラメータにアクセスしたければ、実際の出力パラメータの数に関係なく、$param = $som->paramsout;を呼び出して取得することができます。

クラス関数として呼び出すと(例えばSOAP::SOM::method)、現在の要素にマッチするXPath文字列を返します('method'の場合は'/Envelope/Body/[1]')。このメソッドは、存在しないかまたはxsi:null="1"属性を持つ要素にアクセスしようとしたときにはundefを返します。これら2つの場合を切り分けるには、最初にmatch()メソッドでアクセスすることができます。それはブール値コンテキストではtrue/falseを返します、そして実際の値を取得します:

  if ($som->match('//myparameter')) {
    $value = $som->valueof; # これはundefになるかも
  } else {
    # 存在しない
  }

root()
ルート要素の値を(ハッシュで)返します。$som->valueof('/')がするのと全く同じです。
envelope()
Envelope要素の値を(ハッシュで)返します。このハッシュのキーは(もしあれば)'Header'、'Body'そしてその他(オプション)の要素になります。値はそれぞれデシリアライズされたヘッダ、本体、要素になります。関数として(SOAP::SOM::envelope)呼ばれると、エンベロープの内容にマッチするXPath文字列を返します。単にマッチさせ、自分自身で繰り返したいときには便利です。例えば:
  if ($som->match(SOAP::SOM::envelope)) {
    $som->valueof('Header'); # もしあればヘッダへのアクセスを提供
    $som->valueof('Body');   # 本体へのアクセスを提供
  } else {
    # ウーン、SOAPをしてるんじゃないの?
  }

header()
Header要素の値を(ハッシュで)返します。ヘッダのすべての属性にアクセスしたければ、以下のようにしてください:
  # 要素をSOAP::Data オブジェクトとして取得
  $transaction = $som->match(join '/', SOAP::SOM::header, 'transaction')->dataof;
  # すると'transaction'要素のすべての属性にアクセスすることができます
  $transaction->attr; 

headers()
デシリアライズされたヘッダを持つ値のノードセットを返します。heder()とheaders()メソッドの違いは前者はヘッダ全体へのアクセスを提供し、後者は'Header'タグの内側のヘッダへのアクセスを提供する点です:
  $som->headerof(join '/', SOAP::SOM::header, '[1]');
  # 最初のヘッダをSOAP::Headerオブジェクトとして提供

  ($som->headers)[0];
  # 最初のヘッダの値を取得、以下のものと同じ
  $som->valueof(join '/', SOAP::SOM::header, '[1]');

  $som->header->{name_of_your_header_here}
  # name_of_your_header_hereの値を提供

body()
Body要素の値を返します。
fault()
Fault要素の値を(ハッシュで)返します;faultcode、faultstringそしてdetail。Fault要素があれば、result(), paramsin(), paramsout() そして method()はundefを返します。
faultcode()
もしあればfaultcode要素をなければundefを返します。
faultstring()
もしあればfaultstring要素をなければundefを返します。
faultactor()
もしあればfaultactor要素をなければundefを返します。
faultdetail()
もしあればdetail要素をなければundefを返します。
method()
method要素の値を返します(デシリアライズされたリクエスト・エンベロープでそれを呼び出せばすべての入力パラメータ、そしてデシリアライズされたレスポンス・エンベロープで呼び出せば、result/outputパラメータ)。もし'Fault'要素があればundefを返します。
result()
メソッド呼び出しの結果の値を返します。実際には、method要素の子供要素の(ドキュメント順での)最初の要素を返します。
paramsin()
渡されたすべてのパラメータの値を返します。
paramsout()
出力パラメータの値を返します。
Returns value(s) of the output parameters.
paramsall()
結果と出力パラメータの値を1つの配列で返します。
 

SOAP::Schema

SOAP::Schemaはスキーマをロードし、これらのスキーマに従ったスタブを作成する能力を提供します。異なった書き方が提供されます:

stubmaker スクリプトでスタブを作成することができます:

  perl stubmaker.pl http://www.xmethods.net/sd/StockQuoteService.wsdl

そして1行でSOAPサービスにアクセスできるようになります:

  perl "-MStockQuoteService qw(:all)" -le "print getQuote('MSFT')" 

または動的に:

  perl "-MSOAP::Lite service=>'file:./quote.wsdl'" -le "print getQuote('MSFT')"

スタブをサポートされているその他の書き方は:

スキーマのサポートは現在のところ限定されます。モジュールは数多くの異なるスキーマでテストされましたが、複雑なオブジェクトは理解せず、WSDLでのみ機能します。

SOAP::Trace

SOAP::Trace はSOAP::Liteライブラリのためのtrace/debug機能を提供します。これを有効にするには、SOAP::Liteのトレース可能なイベント/部分のリストを指定する必要があります:

  use SOAP::Lite +trace =>
    qw(list of available traces here);

使用可能なイベントは以下のものがあります:

 transport  -- (client) 転送レイヤのためのrequest/response へのアクセス
 dispatch   -- (server) 呼び出された呼び出しのフルネームを表します
 result     -- (server) メソッド呼び出しの結果
 parameters -- (server) メソッド呼び出しのためのパラメータ
 headers    -- (server) 受信されたメッセージのヘッダ
 objects    -- (both)   new/DESTROY 呼び出し
 method     -- (both)   '->envelope(method =>'呼び出しのためのパラメータ
 fault      -- (both)   '->envelope(fault =>' 呼び出しのためのパラメータ
 freeform   -- (both)   '->envelope(freeform =>' 呼び出しのためのパラメータ
 trace      -- (both)   ある重要な関数へtraceを入れる
 debug      -- (both)   転送についての詳細

例えば:

  use SOAP::Lite +trace =>
    qw(method fault);

は、すべての失敗/通常エンベロープのためのパラメータをSTDERRに出力させます。もしログを取りたければ、STDERRを何か他のファイルにリダイレクトさせることができます。

  BEGIN { open(STDERR, '>>....'); }

または(より好まれることに)特定のイベントのための独自の関数を定義することができます:

  use SOAP::Lite +trace =>
    method => sub {'log messages here'}, fault => \&log_faults;

いくつかのイベントで同じ関数を共有することもできます:

  use SOAP::Lite +trace =>
    method, fault => \&log_methods_and_faults;

またすべての利用可能なトレースを取得するために'all'を使い、イベントの前に'-'を使うことにより特定のイベントを利用不能とすることができます:

  use SOAP::Lite +trace =>
    all, -transport; # to get all logging without transport messages

最後に

  use SOAP::Lite +trace; 

はすべてのデバッグを有効にします。

'trace'の代わりに'debug'を使うことができます。私は'trace'が好きですが、他の人は'debug'が好きです。同様に以下のように、on_debugも後方互換性のために利用可能です。

  use SOAP::Lite;

  my $s = SOAP::Lite 
    -> uri('http://tempuri.org/')
    -> proxy('http://beta.search.microsoft.com/search/MSComSearchService.asmx')
    -> on_debug(sub{print@_}) # show you request/response with headers
  ;
  print $s->GetVocabulary(SOAP::Data->name('~:Query' => 'something'))
          ->valueof('//FOUND');

または以下のように個別に有効にします:

  use SOAP::Lite +trace => debug;

もしくは

  use SOAP::Lite +trace => debug => sub {'do_what_I_want_here'};

以下のものと比較してみてください:

  use SOAP::Lite +trace => transport;
 

これは実際のrequest/responseオブジェクトへのアクセスを提供します。そのためクッキーを設定/読込をおこなったり、そこでやりたいことのすべてを行うことができます。

debugとtransportの違いはtransportはHTTP::Request/HTTP::Responseオブジェクトを取得し、debugは(オブジェクトではなく!)文字列化されたリクエストを取得することで。これは他の場所でも呼び出すことができます。

SOAP::Fault

このクラスはサーバー側で生成されたFaultへのアクセスを提供します。Faultメッセージを作成するには、サーバー側で単にdieするだけです。SOAPプロセッサはfaultstring要素としてメッセージをくるみ、Faultをクライアント側へ転送します。しかしいくつかの場合には、この処理により多くの制御をする必要があり、そしてSOAP::Faultクラスはそれを提供します。これを使うには単にSOAP::Faultオブジェクトをパラメータとしてdieします。

  die SOAP::Fault->faultcode('Server.Custom') # will be qualified
                 ->faultstring('Died in server method')
                 ->faultdetail(bless {code => 1} => 'BadError')
                 ->faultactor('http://www.soaplite.com/custom');

faultdetail() と faultactor() メソッドはオプションで、faultcodeとfaultstringはfaultメッセージではあることが必要とされるので、もしなければSOAP::Liteはデフォルト値を使います('Server'そして'Application error')。


機能とオプション

デフォルト設定

この機能はautodispatch と似ているように見えますが、これらは(ほとんど)共通のものを持ちません。それはデフォルト・オブジェクトを作らせ、すべてのその後に作られるすべてのオブジェクトはデフォルトからクローンされ、そのためそのプロパティを取得します。もし共通のproxy()やurt()設定をあなたのアプリケーションでのすべてのSOAP::Liteオブジェクトに提供したければ、以下のようにすることができます:

  use SOAP::Lite
    proxy => 'http://localhost/cgi-bin/soap.cgi',
    uri => 'http://my.own.com/My/Examples'
  ;
  my $soap1 = new SOAP::Lite; # 上と同じproxy()/uri() を取得
  print $soap1->getStateName(1)->result;
  my $soap2 = SOAP::Lite->new; # 上と同じ
  print $soap2->getStateName(2)->result;
  # もしくは欲しい設定をすべてオーバーライドすることもできます
  my $soap3 = SOAP::Lite->proxy('http://localhost/'); 
  print $soap3->getStateName(1)->result;

すべての SOAP::Lite プロパティをこのようにして伝播させることができます。オブジェクトのコピーでの変更はグローバルな設定には影響を与えません。そしてグローバル・オブジェクトへのリファレンスを返すSOAP::Lite->self 呼び出しでグローバル設定を変更することもできます。提供されたパラメータはこのオブジェクトを更新し、それをundefに設定することさえできます:

  SOAP::Lite->self(undef);

use SOAP::Lite の書き方もプログラムのためのデフォルトのイベント・ハンドラを指定させます。異なるSOAPオブジェクトを持っていて、同じon_action(もしくはそのことについてのon_fault())ハンドラを共有したいならば、各オブジェクトの初期化のさいにon_action()を指定することもできますが、以下のようにするこもとできます:

  use SOAP::Lite 
    on_action => sub {sprintf '%s#%s', @_}
  ;

すると、このハンドラはあなたのすべてのSOAPオブジェクトのためのデフォルトのハンドラになります。特定のオブジェクトのためにハンドラを指定すれば、それをオーバーライドすることもできます。on_fault()ハンドラの例についてはt/*.t をご覧ください。

use ... はコンパイル時にスクリプトが実行される前にすべてのステートメントが実行されるために、予想されない結果となるかもしれないことに注意してください。以下のコードについて考えてみてください:

  use SOAP::Lite proxy => 'http://localhost/';
  print SOAP::Lite->getStateName(1)->result;
  use SOAP::Lite proxy => 'http://localhost/cgi-bin/soap.cgi';
  print SOAP::Lite->getStateName(1)->result;

SOAP 呼び出しは両方とも'http://localhost/cgi-bin/soap.cgi' にいきます。実行時に実行したければ、evalに入れてください:

  eval "use SOAP::Lite proxy => 'http://localhost/cgi-bin/soap.cgi'; 1" or die;

または以下のようにしてください

  SOAP::Lite->self->proxy('http://localhost/cgi-bin/soap.cgi');

IN/OUT, OUT パラメータと自動バイディング

SOAP::Lite はすべてのパラメータへのアクセスを提供します(in/out そしてout)。そしてさらに追加の動きもします。以下のれいについて考えてみましょう:

  <mehodResponse>
    <res1>name1</res1>
    <res2>name2</res2>
    <res3>name3</res3>
  </mehodResponse>

その場合:

  $result = $r->result; # 'name1'を提供
  $paramout1 = $r->paramsout;      # スカラコンテキストなので 'name2'を提供
  $paramout1 = ($r->paramsout)[0]; # 同様に 'name2'を提供
  $paramout2 = ($r->paramsout)[1]; # 'name3'を提供

または

  @paramsout = $r->paramsout; # outパラメータのARRAYを提供
  $paramout1 = $paramsout[0]; # ($r->paramsout)[0]と同じように'res2'
  $paramout2 = $paramsout[1]; # ($r->paramsout)[1]と同じように'res3'

一般的に、サーバーがreturn (1,2,3)を返せば、1を結果(result)、2と3をoutパラメータとして取得します。

もしサーバーがreturn [1,2,3]を返せば、result()から配列を取得し、paramsout()からはundefを取得します。結果(result)は任意に複雑にすることができます。何かの配列にしたり、オブジェクトにしたり、何にでもすることができ、それでもresult()によって返されます。1つのパラメータが返されると、paramsout()はundefを返します。

しかしそれ以上のことがあります。もし出力パラメータに入力パラメータと同じ符号(名前+型)のパラメータを持っていれば、自動的に入力パラメータにマップされます。

サーバー

  sub mymethod {
    shift; # オブジェクト/クラス リファレンス
    my $param1 = shift;
    my $param2 = SOAP::Data->name('myparam' => shift() * 2);
    return $param1, $param2;
  }

クライアント

  $a = 10;
  $b = SOAP::Data->name('myparam' => 12);
  $result = $soap->mymethod($a, $b);

こうすると、 $result == 10 そして $b->value == 24!魔法みたいだ?ある種の自動バインディグがこれを実現しています。オブジェクト・パラメータの名前や型を心配する必要がないという1つの点を除いてオブジェクトについても同様に作用します。PingPongの例について考えてみましょう(examples/My/PingPong.pmexamples/pingpong.pl):

サーバー:

  package My::PingPong;

  sub new { 
    my $self = shift;
    my $class = ref($self) || $self;
    bless {_num=>shift} => $class;
  }

  sub next {
    my $self = shift;
    $self->{_num}++;
  }

クライアント:

  use SOAP::Lite +autodispatch =>
    uri => 'urn:', 
    proxy => 'http://localhost/'
  ;

  my $p = My::PingPong->new(10); # $p->{_num} is 10 now, real object returned 
  print $p->next, "\n";          # $p->{_num} is 11 now!, object autobinded

AUTODISPATCHINGとSOAP:: PREFIX

警告: autodispatch 機能はUNIVERSAL::AUTOLOADのオーバーロードのために、アプリケーションに副作用を与え、他のモジュール/ライブラリに機能的な影響を与えるかもしれません。すべての未解決の呼び出しはSOAP呼び出しとして呼び出されます。場合によってはそうであって欲しくないかもしれませんが。もしそうであればオブジェクト・インターフェース(OOインターフェースの実装をご覧ください)を使うことをお考えください。

SOAP::Lite はautodispatching 機能を提供しており、これによりローカルとリモートのアクセスを同じように見えるプログラムを書くことができます。

例えば:

  use SOAP::Lite +autodispatch =>
    uri => 'urn:/My/Examples', 
    proxy => 'http://localhost/'
  ;

は SOAP に すべての呼び出しを'http://localhost/'エンドポイントに'urn:/My/Examples' uriで自動呼出しするように伝えます。この結果、メソッド呼び出しは以下のようになります:

  print getStateName(1), "\n";
  print getStateNames(12,24,26,13), "\n";
  print getStateList([11,12,13,42])->[0], "\n";
  print getStateStruct({item1 => 10, item2 => 4})->{item2}, "\n";

見てのとおり、SOAP特有のコーディングは何もありません。

同じロジックがオブジェクトについても機能します:

  print "Session iterator\n";
  my $p = My::SessionIterator->new(10);     
  print $p->next, "\n";  
  print $p->next, "\n";   

これはリモートのMy::SessionIterator モジュールにアクセスし、オブジェクトを取り出し、そして再びリモートのメソッドを呼び出します。オブジェクトはサーバーに転送され、メソッドがそこで実行され、結果(そして更新されたオブジェクト!)がクライアントに転送され戻ってきます。

Autodispatch は、プログラムに同じメソッドを持っていないときにだけ機能します。例えばuse My::SessionIteratorを前の例のプログラムのどこかで持っていれば、すべてのメソッドはローカルに解決され、SOAP呼び出しは何もおこなわれません。そのような場合でもリモートのオブジェクト/メソッドにアクセスしたければ、以下のようにメソッドの前にSOAP::をつけてください:

  print $p->SOAP::next, "\n";  

スクリプトの例としてはpingpong.pl をご覧ください、それはローカルとリモートに同じオブジェクトで動きます。

SOAP:: 接頭辞 はSOAP::Liteそれ自身と同じ名前をもつメソッドへの任意のアクセスを提供します。たとえばOOインタフェースでクラスMy::PingPongのためのnew()メソッドを呼び出したいとします。最初にやろうとすると:

  my $s = SOAP::Lite 
    -> uri('http://www.soaplite.com/My/PingPong')
    -> proxy('http://localhost/cgi-bin/soap.cgi')
  ;
  my $obj = $s->new(10);

しかしこれは動きません。SOAP::Liteがメソッドnew()を持っているからです。ヒントを与えるためにSOAP::を前につければ、呼び出しはリモートに呼び出されます:

  my $obj = $s->SOAP::new(10);

必要であればautodispatchと通常のSOAP呼び出しを同じプログラムで混ぜることができます。SOAP::を前につけた呼び出しは常にメソッド呼び出しでなければならないことに気をつけてください。そのため関数を呼び出したければ、SOAP::myfunction()の代わりにSOAP->myfunction()を使ってください。

Perlが非常に柔軟な書き方を持っているからといっても、'autodispatch' と'=>'を別の行に置こうとすると、バージョンによっては以下のように怒らることに注意してください

  Bareword "autodispatch" not allowed while "strict subs" in use ...

そのため同じ行にするか、'autodispatch'をクォートで囲むかしてください:

  use SOAP::Lite 'autodispatch' # この場合にはプラスを使わないでください
    => .... 
  ; 

サーバー側でヘッダとエンベロープにアクセスする

SOAP::Liteはサーバー側ですべてのヘッダとエンベロープ全体への直接アクセスを提供しています。My::Parameters.pmからの以下のコードについて考えてみましょう:

  sub byname { 
    my($a, $b, $c) = @{pop->method}{qw(a b c)};
    return "a=$a, b=$b, c=$c";
  }

SOAP::Server::Parametersクラスからクラスを継承した場合にのみ、この機能を取得できます。これにより既存のプログラムをそのままに、必要なときにだけこの機能を提供します。

サーバー側のすべてのメソッドはクラス/オブジェクト メソッドとして呼び出されます。そのため最初のパラメータとしてオブジェクト・リファレンスまたはクラス名を、そしてメソッド・パラメータ、SOAP::SOMオブジェクトでのエンベロープを取得します。まとめると:

  $self [, @parameters] , $envelope

決まった数のパラメータであれば、以下のようにすることができます:

  my $self = shift;
  my($param1, $param2) = @_;

そしてエンベロープを無視します。エンベロープにアクセスする必要があれば、以下のようにできます:

  my $envelope = pop; 

というのもエンベロープは常にパラメータリストの最後の要素だからです。byname()メソッドpop->methodはパラメータ名をハッシュ・キーとし、ハッシュの値をパラメータ値とするハッシュを返します:

  my($a, $b, $c) = @{pop->method}{qw(a b c)};

これは、パラメータへの名前によるアクセスを提供します。

サービスの展開 静的と動的

展開プロセスについて詳しく見ていきましょう。SOAPサーバーを設計するさい、2種類の展開を考えることができます。静的(static)と動的(dynamic)です。静的と動的の両方とも、SOAP::Liteモジュールを使って作成するさいにはモジュール、モジュール::メソッド、またはパスを指定しなければなりません。静的と動的展開の違いは、「動的」な場合、要求のさいに、すべての存在しないモジュールがロードされるということです。詳しい説明については"セキュリティ" をご覧ください。

静的展開の例:

  use SOAP::Transport::HTTP;
  use My::Examples;           # モジュールはあらかじめロードされます

  SOAP::Transport::HTTP::CGI
    # 展開されるモジールはここになければなりません。そうでなければクライアントは「アクセスが拒否されました」('access deied')を受け取ります
    -> dispatch_to('My::Examples') 
    -> handle;

動的展開の例:

  use SOAP::Transport::HTTP;
  # 名前はわかりません、モジュールは要求のさいにロードされます

  SOAP::Transport::HTTP::CGI
    # 展開されるモジールはここになければなりません。そうでなければクライアントは「アクセスが拒否されました」('access deied')を受け取ります
    -> dispatch_to('/Your/Path/To/Deployed/Modules', 'My::Examples') 
    -> handle;

静的展開では、モジュール名を直接指定しなければなりません。動的展開では名前を直接(その場合は何も制約なしに要求されます)またはパスで間接的に指定することができます。その場合、利用できる唯一のパスは、dispatch_to()メソッドに渡されたパスになります。この場合の取り扱いについてのさらなる情報は"セキュリティ" セクションをご覧ください。

1つのファイルの中に数多くの異なるクラスを持っているとき、それをSOAP呼び出しで使いたい場合にも、静的バインディングを使わなければなりません。

まとめ:

  dispatch_to(
    # 動的ディスパッチ 指定されたディレクトリのすべてのモジュールへのアクセスを可能にします
    PATH/TO/MODULES          
    # 1. ディレクトリの指定
    # -- そして --
    # 2. 制限なしにこのディレクトリに入っているすべてのモジュールへのアクセスを提供

    # 静的ディスパッチ 特定のモジュールのすべてのメソッドへのアクセスを可能にします
    MODULE 
    #  1. 特定のモジュール(利用可能なすべてのメソッド)へのアクセスを提供します
    #  事前に必要なこと:
    #    主導でモジュールをロードされなければなりません (例えば 'use ...'で)
    #    -- または --
    #    PATH/TO/MODULESで指定することもできます

    # 静的ディスパッチ 特定のメソッドだけへのアクセスを可能にします
    MODULE::method 
    # MODULEと同じ。しかし特定のメソッドだけへのアクセスを提供します。
    # そのため同じモジュールに対してMOULEとMODULE::methodの両方を指定する
    # ことはあまり意味がありません
  )

これに加えてSOAP::Liteは特定のURLまたはSOAPActionをCLASS/MODULEまたはオブジェクトに結びつけることを可能にする実験的な書き方をサポートしています。

  dispatch_with({
    URI => MODULE,        # 'http://www.soaplite.com/' => 'My::Class',
    SOAPAction => MODULE, # 'http://www.soaplite.com/method' => 'Another::Class',
    URI => object,        # 'http://www.soaplite.com/obj' => My::Class->new,
  })

URI はSOAPActionの前にチェックされます。dispatch_to()とdispatch_withの両方の書き方を使うことができます。そしてdispatch_with()のほうが優先されます。そのため最初にURI、そしてSOAPActionがチェックされ、その後にdispatch_to()がチェックされます。更なる情報と例については、 t/03-server.t をご覧ください。

セキュリティ

セキュリティ上の理由から、、動的展開を選択し、独自のPATH/を指定するとperlモジュールのためのカレント・パス(@INC)は使えなくなります。もしインクルードされるパッケージで他のモジュールにアクセスしたければ、いくつかの方法があります:

  1. 静的リンクに切り替える:
       use MODULE;
       $server->dispatch_to('MODULE');
    
    

    展開されたモジュールから何か特定のものをインポートしたときにも便利です。

       use MODULE qw(import_list);
    
  2. useをrequireに変更する。パスは初期化部分でのみ利用できなくなります。そして実行時点では再び利用できます。そこでパッケージのどこかでrequireをするならば、それは動きます。
  3. 同じこと。しかし以下のようにもできます:
       eval 'use MODULE qw(import_list)'; die if $@;
    
  4. パッケージの中で@INCディレクトリに代入し、useする。BEGIN{}ブロックで@INCに入れることを忘れないでください。そうでなければ動きません:
       BEGIN { @INC = qw(my_directory); use MODULE }
    
    

圧縮

SOAP::Lite は送信上での圧縮を可能とするオプションを提供します(HTTP転送のみ)。サーバーとクライアントの両方でこの機能をサポートしなければなりません、しかしこのロジックはアプリケーションにとってはまったく透過的です。

圧縮はクライアントまたはサーバー側で圧縮のための閾値を指定することにより可能になります:

クライアント
  print SOAP::Lite
    -> uri('http://localhost/My/Parameters')
    -> proxy('http://localhost/', options => {compress_threshold => 10000})
    -> echo(1 x 10000)
    -> result
  ;


サーバー

  my $server = SOAP::Transport::HTTP::CGI
    -> dispatch_to('My::Parameters')
    -> options({compress_threshold => 10000})
    -> handle;

さらなる情報についてはHTTP転送ドキュメントのCOMPRESSIONセクション をご覧ください。

参照によるオブジェクト

SOAP::Lite は参照によるオブジェクト(objects-by-reference)実験敵意(まだ機能的)サポートをしています。これを使うとクライアント側と違いが何も見つからないでしょう。サーバー側では、サーバー実装のためのobjects_by_reference()メソッドで参照(値ではなく)で返したいクラスの名前を指定しなければなりません(soap.pop3、soap.daemonそしてApache.pmをご覧ください)

サーバー側でガベージ・コレクションは行われます(動いていない時間が600秒後よりも早くなく)。そしてすべての特定のクラスのための特定の関数でデフォルトの動きをオーバーロードすることができます。

バイデンィグは特別な書き方はなく、サーバー側で実装されます(My::SessionIteratorとMy::PersistentIteratorとの違いをご覧ください)。クライアント側では、オブジェクトは前と同じ型/クラスを持ちます。(My::SessionIterator->new()はクラスMy::SessionIteratorのオブジェクトを返します)。しかしこのオブジェクトは内側ではオブジェクトIDを持ったスタブに過ぎません。

相互互換性

Microsoft's .NET
.NET クライアントと SOAP::Lite サーバーを使うには
すべての要素を修飾する
戻り値のために完全に修飾された名前を使ってください。例えば:
  return SOAP::Data->name('~:myname')->type('string')->value($output);

さらに下記の.NET Webサービスでデフォルトで書かれているプログラムについてのコメントをご覧ください。

SOAP::Lite クライアントと .NET サーバー

呼び出しで適切なsoapAction(uri/method)を宣言する
例えばon_action(sub{join '', @_})を使ってください。
すべての要素を修飾する
以下のことはすべて機能します:
メソッド・パラメータに完全修飾名を利用する
SOAP::Data->name('Query' => 'biztalk') の代わりに SOAP::Data->name('~:Query' => 'biztalk') を使ってください。

SOAPsh 呼び出しの例(すべてのパラメータは1行でなければなりません)

  > perl SOAPsh.pl 
    "http://beta.search.microsoft.com/search/mscomsearchservice.asmx" 
    "http://tempuri.org/" 
    "on_action(sub{join '', @_})" 
    "GetVocabulary(SOAP::Data->name('~:Query'  => 'biztalk'))"

デフォルトの名前空間でメソッドを作る
 
  my @rc = $soap->call(add => @parms)->result;
  # -- または --
  my @rc = $soap->add(@parms)->result;

とする代わりに

  my $method = SOAP::Data->name('add')
                         ->attr({xmlns => 'http://tempuri.org/'});
  my @rc = $soap->call($method => @parms)->result;

としてください。

それを管理しているのであれば.NET サーバーを変更する

Stefan Pharies <stefanph@microsoft.com>:

SOAP::Lite は SOAP エンコーディング (soap1.1 仕様のセクション 5)を使います。そして.NET Webサービスはデフォルトではリテラル・エンコーディングを使います。そのためリクエストのなかの要素は

修飾されませんが、サービスは修飾されることを期待します。.Net Webサービスは期待されるメッセージのフォーマットを変更するための方法をもっています。これは中間の動きを取得することを可能にします。asmxでのクラスの先頭で、この属性を追加してください:

  [SoapService(Style=SoapServiceStyle.RPC)]

Full Web Service テキストとは以下のようになります。 (私が書き方を理解している限りでは):

  <%@ WebService Language="C#" Class="Test" %>
  using System;
  using System.Web.Services;
  using System.Xml.Serialization;

  [SoapService(Style=SoapServiceStyle.RPC)]
  public class Test : WebService {
    [WebMethod] 
    public int add(int a, int b) {
      return a + b;
    }
  }

説明と例について、Petr Janata <petr.janata@i.cz>, Stefan Pharies <stefanph@microsoft.com>, and Brian Jepson <bjepson@jepstone.net> に感謝します。

トラブル・シューティング

HTTP 転送
HTTP転送のためのドキュメントでの トラブルシューティングセクションをご覧ください
COM インターフェース
Can't call method "server" on undefined value
(未定義の値にメソッド"server"を呼ぶことはできません)
おそらくは'regsvr32 Lite.dll'でLite.dllを登録していないでしょう。
Failed to load PerlCtrl runtime
(PerlCtrlランタイムのロードに失敗しました)
おそらくは2つのPerlが異なる場所にインストールされており、ActiveStateのPerlがPATHで指定された最初のPerlではないのでしょう。もう1つのPerlが入っているディレクトリの名前を変え(少なくともDLLのスタートアップの間)、そしてActiveStateのPerlをPATHでの最初の場所に置いてください。


XML Parsers

SAX parsers
SAX 2.0 はorg.xml.sax.helpersにバグがあることが知られています。ParserAdapter は宣言の前で使われた名前空間接頭辞(Namespace prefix)を拒絶します。

(http://www.megginson.com/SAX/index.html).

つまり場合によっては、SOAP::Liteにより作成されたSOAPメッセージがSAX2/Javaパーザーでは適切に解析されないかもしれません。

というのもEnvelope要素は名前空間宣言とこの宣言に依存する属性がが入っているからです。XMLの仕様によれば、これらの属性の順番は重要ではなく、SOAP::Liteは何も問題なくそのようなメッセージを解析します。

これについて指摘してくれたSteve Alpert (Steve_Alpert@idx.com) に感謝します。

パフォーマンス

XMLエンコードされたフラグメントの処理
SOAP::Lite はXML::Parseをベースにしています。それはJames Clarkのexpatパーザーをくるんでいます。ExpatのXMLエンコードされた文字列の解析のための動きは、文字列としてエンコ−ドされたXMLフラグメントのようなエンコードされたエンティティをたくさん持っている処理するメッセージに影響を与えます。
下位レベルの詳細を提供するため、パーザーは処理されるストリームのすべての部分のために、しかし個別には処理されるエンティティまたは改行ごとにchar()コールバックを呼び出します。

それは数多くの呼び出しを導き、小さなメッセージごとの追加のメモリ管理出費をかけさせます。これに対してbase64でエンコードされたXMLメッセージはこの問題がありません。そして違いは処理時間で明確です。だいたい20行、30タグを持っているXMLエンコードされた文字列は、100回ほど呼び出しがありますが、base64でエンコードされた同じ文字列は1回です。

この動きを修正しないのはパーザーの機能ですので(もし何か見つけたら教えてください)、特に既に取得したメッセージを解析する必要があるので(そしてこのメッセージの内容を制御することができないので)、しかしながらもし処理の両端について責任を持っているのであれば、送り側でbase64にエンコーディングを切り替えることができます。これはSOAP::Liteでは間違いなく動きます。他のツールキト/実装でも動くかもしれません。しかし明確にはそれを保証できません。

特定の文字列をbase64でエンコードしたければ、クライアントまたはサーバー側でSOAP::Data->type(base64 => $string) とだけしてください。SOAP::Liteの特定のインスタンスのための動きを変えたければ、SOAP::Serializerをサブクラス化し、文字列のエンコーディングを受け持つas_string()メソッドを(as_base64()を見て)オーバーライドし、そして新しいSerializerクラスをSOAP::Liteオブジェクトに指定します:

  my $soap = new SOAP::Lite
    serializer => My::Serializer->new,
    ..... 他のパラメータ

またはサーバー側:

  my $server = new SOAP::Transport::HTTP::Daemon # or any other server
    serializer => My::Serializer->new,
    ..... 他のパラメータ

SOAP::Liteのすべてのインスタンスのこの動きを変更したければ、use SOAP::Liteの、実際に処理/送信するのどこかで、as_string()メソッドをas_base64()で置き換えるだけです:

  *SOAP::Serializer::as_string = \&SOAP::Serializer::as_base64;

最後2つのメソッドはすべての文字列に影響を与え、それらをbase64エンコードへ変換することに注意してください。SOAP::Liteでは何も違いはありませんが、他のツールキットでは違いがあるかもしれません

WEBホスティングでのインストール

そのマシンにtelnetでアクセスし、XML::Parserが既にインストールされていれば、ホスティング・プロバイダが彼ら自身でやりたがらなくても、SOAP::Liteの独自のコピーをインストールすることができます。

ログインし、.profile(または.bash_profile)にPERL5LIB変数を設定します:

  PERL5LIB=/you/home/directory/lib; export PERL5LIB

ここでの'lib' は、ホームディレクトリの下ですべてのライブラリがインストールされるディレクトリの名前です:

CPAN モジュールを以下のようにして起動します

  perl -MCPAN -e shell

そして以下の3つのコマンドを実行します

  o conf make_arg -I~/lib
  o conf make_install_arg -I~/lib
  o conf makepl_arg LIB=~/lib PREFIX=~ INSTALLMAN1DIR=~/man/man1 INSTALLMAN3DIR=~/man/man3

LIB じゃすべてのライブラリがあるディレクトリを指定します。

PREFIX はすべてのディレクトリのための接頭辞を指定します。(lib, bin, manのような。しかしある理由からすべての場合には機能しません)

INSTALLMAN1DIR と INSTALLMAN3DIR はmanのためのディレクトリを指定します(指定しなければ、デフォルトのディレクトリにセットアップしようとし、あなたはそれに許可を持たないからです)

そうすれば以下のように実行できます:

  install SOAP::Lite

その後、スクリプトには以下のように追加する必要があります:

  use lib '/your/home/directory/lib';

'use SOAP::Lite;'の前のどこかで。これで終わりです。


バグと制限


プラットホーム

MacOS
MacPerlのためのXML::Parserについての情報がここにあります:http://bumppo.net/lists/macperl-modules/1999/07/msg00047.html

MacOSのためのコンパイルされたXML::Parserがここにあります:http://www.perl.com/CPAN-local/authors/id/A/AS/ASANDSTRM/XML-Parser-2.27-bin-1-MacOS.tgz


可用性

SOAP::Lite for Unix やSOAP::lite for Win32の最新バージョンは http://soaplite.com/ からダウンロードすることができます。SOAP::LiteはCPAN( http://search.cpan.org/search?dist=SOAP-Lite )からも利用することができます。コメント、提案、バグレポートそして文句はメールを作者(paulclinger@yahoo.com)へ書くことは歓迎されます。


参考資料

SOAP Keith BrownによるSOAP/Perlライブラリ( http://www.develop.com/soap/ ) または ( http://search.cpan.org/search?dist=SOAP )


謝辞(ACKNOWLEDGMENTS)

(原文のまま)

A lot of thanks to Tony Hong <thong@xmethods.net>, Petr Janata <petr.janata@i.cz>, Murray Nesbitt <murray@ActiveState.com>, Robert Barta <rho@bigpond.net.au>, Gisle Aas <gisle@ActiveState.com>, Carl K. Cunningham <cc@roberts.de>, Graham Glass <graham-glass@mindspring.com>, Chris Radcliff <chris@velocigen.com>, and many many others for provided help, feedback, support, patches and comments.


著作権(COPYRIGHT)

(原文のまま)

Copyright (C) 2000-2001 Paul Kulchenko. All rights reserved.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.


作者(AUTHOR)

(原文のまま)

Paul Kulchenko (paulclinger@yahoo.com)


ホーム Perlの小技

ご意見、ご質問はこちらの掲示板で受け付けています。
またメールは河馬屋(Nifty)にお願いします。